«تایپ اسکریپت» (TypeScript) در قلمرو جاوا اسکریپت محبوبیت قابلتوجهی به دست آورده است و ابزارهایی را برای تیمهای برنامه نویسی فراهم میکند تا با ترکیب ویژگیهای تعیین نوع پویا و ایستا، بهرهوری خود را افزایش دهند. این ویژگیها کاربران را قادر میسازد تا کد واضحتر و توصیفیتری ایجاد کنند که این قابلیت تشخیص و حل زودهنگام خطا را تسهیل میکند. یکی از این ویژگیهای مهم، ویژگی Interface در تایپ اسکریپت است که به عنوان نوعی ابزار کمکی به برنامه نویسان بسیار کمک خواهد کرد. در این مطلب از «مجله فرادرس»، «رابط یا واسط» (اینترفیس | Interface) در تایپ اسکریپت را مورد بررسی و بازبینی قرار خواهیم داد و در سناریوهایی کاملاً عملی به توضیح آن خواهیم پرداخت. کاربران در پایان مطالعه این مطلب درک نسبتاً صحیح و مناسبی از مفهوم Interface در TypeScript به دست خواهند آورد.
مفهوم Interface در تایپ اسکریپت
در زبان برنامه نویسی جاوا اسکریپت، توسعهدهندگان سطح قابلتوجهی از انعطافپذیری را در مورد نوع مقادیر اختصاص داده شده به متغیرها دارند. متغیر که در ابتدا اعلام و مقداری از نوع عدد صحیح به آن اختصاص داده شده است، میتواند متعاقباً با مقدار متفاوت، مانند نوعی تابع، در طول اجرای برنامه تخصیص داده شود. این انعطافپذیری یکی از ویژگیهای تعیین نوع پویا در جاوا اسکریپت است که به متغیرها اجازه میدهد تا نوع خود را به صورت پویا در طول زمان اجرا تغییر دهند.
همانطور که در مثال زیر نشان داده شده است، انواع متغیرها در جاوا اسکریپت از پیش تعیین نشدهاند:
1var a = 2
2a = function () {
3 console.log("I was initialized with a value of an integer, but now I'm a function")
4}
برای درک بهتر این موضوع، سناریوی ساخت خودروی تسلا مدل S
بدون مشخصات از پیش تعریف شده را در قالب مثالی نظر بگیرید. ۱۰ مهندس به طور مستقل نمونههای اولیه را میسازند که هر کدام دارای مجموعهای از مشخصات خاص خود هستند. به عنوان مثال، یک نمونه اولیه ممکن است جزئیات شارژ خودرو را نمایش دهد، در حالی که نمونه دیگر دارای سیستم نظارت بر تایر و غیره است.

اگر مشخصات از قبل تعیین شده بود، مهندسان میتوانستند به مجموعهای از دستورالعملها پایبند باشند و فرآیند پیادهسازی را سادهتر کنند. این به موازات چالشی است که کاربران هنگام ساخت موجودیتهای پیچیده در جاوا اسکریپت با آن مواجه میشوند.
1function buildTeslaModelS (teslaObj) {
2 // Implementation Details
3}
4
5buildTeslaModelS({
6 length: 196,
7 width: 86,
8 measureTirePressure: function () {
9 },
10 wheelbase: 116
11})
12
13buildTeslaModelS({
14 length: "196",
15 width: "86",
16 wheelbase: "116",
17 measureRemCharging: function () {
18 }
19})
تابع buildTeslaModelS
ماشین تسلا مدل S
را بر اساس پارامترهای teslaObj
ارائهشده تولید میکند. با این حال، فرضیاتی را در مورد پارامترهای ورودی ایجاد خواهد کرد و انتظار دارد که طول، عرض و فاصله محوری ویژگیهای اعداد صحیح باشد. در نتیجه، زمانی که این مفروضات برآورده نمیشوند، مانند زمانی که مقادیر به صورت رشته ارائه میشوند، خطاهای زمان اجرا رخ میدهد. علاوه بر این، تابع buildTeslaModelS
فاقد آگاهی از ویژگی measureRemCharging
است که منجر به خطا میشود. buildTeslaModelS
فرض میکند که measureRemCharging
برای همه مدلها اجباری است و در صورت عدم وجود این ویژگی، خطای زمان اجرا ایجاد میشود.
برای افزایش این انعطافپذیری، مکانیزمی برای انتقال ساختار مورد انتظار پارامتر teslaObj
به تابع buildTeslaModelS
موردنیاز است. این امکان بررسی اعتبار سنجی زمان کامپایل را برای ویژگیهای اجباری و انواع آنها فراهم میکند و از اجرای قویتر و مقاومتر در برابر خطا اطمینان میدهد؛ اما مثال بالا چه کمکی بی درک مفهوم Interface در تایپ اسکریپت خواهد کرد؟ در ادامه به این مسئله خواهیم پرداخت.

درک مفهوم Interface در تایپ اسکریپت از مثال بالا
اینترفیس در TypeScript نوعی ابزار ارزشمند برای ارائه ساختار و وضوح در کد است. اساساً، رابط به عنوان نوعی طرح اولیه عمل میکند و بدون دیکته کردن و پیچیدگی خاصی مشخص خواهد کرد که موجودیت باید الزاماتی را برآورده سازد. مثال بالا با نشان دادن نوعی چالش رایج در توسعه جاوا اسکریپت، به ایجاد زمینه برای درک مفهوم اینترفیس در TypeScript کمک میکند. در جاوا اسکریپت، انعطافپذیری انواع متغیر میتواند منجر به مشکلاتی شود، بهویژه هنگام ساخت موجودیتهای پیچیده مانند خودروی تسلا مدل S
بدون مشخصات از پیش تعریف شده. مثال ساخت ماشین تسلا نشان میدهد که بدون ساختار یا قرارداد مشخصی که ویژگیهای مورد انتظار و انواع آنها را تعریف میکند، توسعهدهندگان ممکن است با خطاهای زمان اجرا مواجه شده و در حفظ ثبات در بین پیادهسازیها با مشکلاتی روبهرو شوند.
در زمینه مثال تسلا مدل S
، تایپ اسکریپت به کاربران اجازه میدهد تا نوعی رابط ایجاد کنند که ویژگیها و عملکردهای ضروری را که باید در هر پیادهسازی وجود داشته باشد، مشخص میکند. این رابط یا همان اینترفیس به عنوان نوعی قرارداد عمل کرده و جنبههای ضروری را بدون پرداختن به جزئیات اجرای آنها شرح میدهد. رابط کاربری تسلا مدل اس در اینجا آمده است:
1interface TeslaModelS {
2 length: number;
3 width: number;
4 wheelbase: number;
5 seatingCapacity: number;
6 getTyrePressure: () => number;
7 getRemCharging: () => number;
8}
این رابط بهوضوح ویژگیها را فهرست میکند، انواع آنها را مشخص کرده و توابعی مانند getTyrePressure
و getRemCharging
را تعیین خواهد کرد. همچنین این رابط انواع بازگشت آنها را با جزئیات توضیح میدهد. با پایبندی به این رابط، توسعهدهندگان میتوانند پیادهسازیهای سازگار و قابلاعتمادی از تسلا مدل S
ایجاد کنند و کیفیت کد را ارتقاء داده و احتمال خطا را کاهش دهند. همچنین در مثال فوق اکنون، هنگام استفاده از این رابط، تایپ اسکریپت بررسیهای زمان کامپایل را برای اطمینان از مطابقت اشیا ارسال شده به توابعی مانند buildTeslaModelS
با ساختار تعریف شده ارائه میدهد. این ویژگی به شناسایی خطاهای احتمالی در مراحل اولیه توسعه کمک میکند و ثبات کد را ارتقا میدهد.
نحوه استفاده از رابط در تایپ اسکریپت
برای استفاده از Interface در تایپ اسکریپت، وجود نوعی کلاس یا تابع میتواند این رابط را برای مشخص کردن پیادهسازی خاصی آماده کند. بیاید اجرای تابعی را در نظر بگیریم که به رابط TeslaModelS
پایبند است و تا حدود زیادی درک رفتار و نحوه ساخت اینترفیس را برای ما مشخص خواهد کرد:
1function buildTeslaModelS(teslaObj: TeslaModelS) {
2}
تلاش برای فراخوانی این تابع با شیئی که با اینترفیس هماهنگ نیست، نوعی خطای کامپایلر تایپ اسکریپت را ایجاد میکند، همانطور که در زیر نشان داده شده است:
1buildTeslaModelS({
2 length: "196",
3 width: "86",
4 wheelbase: "116",
5 measureRemCharging: function () {
6 }
7})
کامپایلر به دو دلیل زیر خطا ایجاد میکند:
- طول، عرض و «فاصله بین دو محور» ( wheelbase
) انتظار میرود در ساخت ماشین از نوع عددی باشند اما به صورت رشتهها ارائه میشوند.
- ویژگی measureRemCharging
در رابط تعریف نشده است. این ویژگی باید getRemCharging
نامیده شود و نوعی عدد صحیح بازگرداند تا از انطباق با قرارداد رابط اطمینان حاصل کند.
برای انطباق با رابط و ساخت تسلا مدل S
، تابع باید به صورت زیر اجرا شود:
1function buildTeslaModelS (teslaObj: TeslaModelS) {
2}
3
4buildTeslaModelS({
5 length: 196,
6 width: 86,
7 wheelbase: 116,
8 seatingCapacity: 4,
9 getTyrePressure: function () {
10 let tyrePressure = 20 // Evaluated after doing a few complex computations!
11 return tyrePressure
12 },
13 getRemCharging: function () {
14 let remCharging = 20 // Evaluated after doing a few complex computations!
15 return remCharging
16 }
17})
این پیادهسازی دقیقاً با انتظارات ذکر شده در رابط مطابقت دارد و اطمینان میدهد که شی ارائه شده به ساختار و عملکرد مشخص شده پایبند است.

تعیین Duck Typing در تایپ اسکریپت چیست؟
«تعیین نوع اردکی» (Duck Typing) که به عنوان زیر مجموعه یا بخشی از تعیین نوع ساختاری نیز شناخته میشود، نقش مهمی در بررسی نوع در تایپ اسکریپت ایفا میکند. این نوع سیستم بهجای نوع یا کلاس صریح، بر ارزیابی ساختار و شکل شی تمرکز دارد. در تایپ اسکریپت، تعیین نوع اردکی بررسی میکند که آیا شی یا مقدار، دارای ویژگیها و متدهای لازم در طول زمان کامپایل است یا خیر. این کار بدون تکیهبر سلسلهمراتب کلاسها یا رابطهای از پیش تعریف شده، انجام میگیرد.
بیایید اهمیت تعیین نوع اردکی را به وسیله Interface در تایپ اسکریپت با مثالی گویا بررسی کنیم:
1interface Animal {
2 name: string;
3 makeSound(): void;
4}
5
6class Dog implements Animal {
7 name: string;
8
9 constructor(name: string) {
10 this.name = name;
11 }
12
13 makeSound(): void {
14 console.log('Woof!');
15 }
16}
17
18class Cat implements Animal {
19 name: string;
20
21 constructor(name: string) {
22 this.name = name;
23 }
24
25 makeSound(): void {
26 console.log('Meow!');
27 }
28}
29
30function playWithAnimal(animal: Animal): void {
31 console.log(`Playing with ${animal.name}`);
32 animal.makeSound();
33}
34
35const dog = new Dog('Max');
36const cat = new Cat('Mittens');
37
38playWithAnimal(dog); // Output: Playing with Max
39playWithAnimal(cat); // Output: Playing with Mittens
در مثال بالا، اینترفیس یا همان رابط Animal
الزامات ضروری نوعی حیوان را مشخص میکند و ویژگی name
و متد makeSound
را برای آن مشخص خواهد کرد. کلاسهای Dog
و Cat
این رابط را پیادهسازی میکنند و مطمئن میشوند که دارای ویژگیها و متدهای لازم مطابق با توابعی هستند که آرگومان Animal
را میپذیرند. تابع playWithAnimal
با بررسی نکردن کلاس خاص آرگومان Animal
، تعیین نوع اردکی را مثال میزند و بررسی میکند که آیا شی دارای ویژگی name
و متد makeSound
است. این رویکرد امکان تعریف اشیا را بدون مواجهه با خطا فراهم میکند.

در حالی که تعیین نوع اردکی روشی قدرتمند محسوب میشود، مهم است که توجه داشته باشیم که جایگزین بررسی نوع صریح نمیشود. بررسی نوع صریح مزایای ارزشمندی از جمله تشخیص زودهنگام خطاهای نوع در طول کامپایل و بهبود خوانایی کد ارائه میدهد.
تفاوت اینترفیس و انواع در تایپ اسکریپت
در حالی که انواع و اینترفیس در تایپ اسکریپت هدف مشترک تعریف اشکال و ساختارها را دارند اما اهداف متفاوتی را نیز دنبال میکنند و هر کدام برای سناریوهای مختلف مناسب هستند. در اینجا مروری مختصر از تمایزات کلیدی بین رابطها و انواع در هنگام تعریف اشکال آورده شده است:
ویژگیها و کاربردهای Interface در تایپ اسکریپت شامل فهرست موارد زیر است:
- هدف اولیه: در درجه اول برای تعریف قرارداد برای اشیا استفاده میشوند.
- جزئیات پیادهسازی: رابطها صرفاً بر تعریف ساختار بدون ترکیب جزئیات پیادهسازی تمرکز میکنند.
- انعطافپذیری: آنها در نمایش ساختارهای مختلف تطبیقپذیری کمتری دارند.
- اجرای قرارداد: قراردادها را برای ویژگیهای شی سختگیرانه اجرا میکند.
ویژگیها و کاربردهای نوع در تایپ اسکریپت شامل فهرست موارد زیر است:
- هدف اولیه: برای نمایش ساختارهای مختلف، از جمله اشکال، استفاده میشود اما به قراردادهای شی محدود نمیشود.
- جزئیات پیادهسازی: میتوانند شامل جزئیات پیادهسازی همراه با تعریف شکل باشند.
- انعطافپذیری: از آنچه میتوانند نشان دهند، انعطافپذیرتر هستند.
- اجرای قرارداد: قرارداد سختگیرانهای را اجرا نمیکنند اما میتوانند اطلاعات نوع را ارائه دهند.
اینترفیس در تایپ اسکریپت برای توصیف اشکال اشیا، اجرای قراردادها و اطمینان از ثبات در ساختارهای کلاس مناسب هستند. از سوی دیگر، انواع در مدیریت تعیین نوع پیچیده، مدیریت دادههای غیر شی و تعریف نوع برای کتابخانههای خارجی برتری دارند. انتخاب بین اینترفیس و انواع به نیازهای خاص پروژه و ماهیت دادهها یا ساختارهایی که با آنها سروکار داریم بستگی دارد. استفاده از هر دو در پایگاه کد تایپ اسکریپت به کاربر این امکان را میدهد که از نقاط قوت آنها در بخشهای مختلف برنامه خود استفاده کند.
توابع Interface در تایپ اسکریپت
توابع اینترفیس در تایپ اسکریپت که بهعنوان انواع تابع نیز شناخته میشوند، راهی برای تعریف ساختار توابع در تایپ اسکریپت ارائه میدهند. توابع اینترفیس به ویژه زمانی مفید هستند که کاربر بخواهد به طور صریح انواع پارامترهایی را که تابع باید بپذیرد و نوع آن را باید بازگرداند، مشخص کند. در اینجا مثالی از نحوه تعریف و استفاده از نوعی تابع اینترفیس در تایپ اسکریپت آورده شده است:
1interface Calculator {
2 (a: number, b: number): number;
3}
4
5const add: Calculator = (a, b) => a + b;
6const subtract: Calculator = (a, b) => a - b;
7
8console.log(add(5, 3)); // 8
9console.log(subtract(10, 4)); // 6
در مثال بالا، رابط ساختار تابعی را مشخص میکند که دو پارامتر از نوع عدد را میگیرد و عددی را بازمیگرداند. این رابط به عنوان طرحی برای توابعی مانند add
و subtract
عمل میکند و از مطابقت آنها با امضای مشخصشده اطمینان میدهد. رابطهای تابع نقش مهمی در اجرای اشکال تابع سازگار، بهبود وضوح کد و تسهیل تشخیص زودهنگام خطاهای مربوط به تعیین نوع در مرحله توسعه ایفا میکنند.

نحوه تعریف ویژگی های اختیاری در رابط ها
در رابطه با مفهوم Interface در تایپ اسکریپت، اغلب از موجودیتها میخواهیم که به ویژگیهای خاصی پایبند باشند. با این حال، موقعیتهایی وجود دارد که همه ویژگیها اجباری نیستند و اینجاست که ویژگیهای اختیاری وارد عمل میشوند. برای نشان دادن نوعی ویژگی اختیاری در رابط یا اینترفیس، از علامت یا نماد ?
استفاده میشود. برای درک بهتر این موضوع مثالی از رابط TeslaModelS
را در نظر بگیرید:
1interface TeslaModelS {
2 length: number;
3 width: number;
4 wheelbase: number;
5 seatingCapacity: number;
6 getTyrePressure?: () => number;
7 getRemCharging: () => number;
8}
در مثال فوق ?
بعد از getTyrePressure
نشان میدهد که این ویژگی اختیاری است. کاربرانی که این رابط را پیادهسازی میکنند موظف به ارائه این قابلیت در همه موارد نیستند و کامپایلر تایپ اسکریپت در صورت حذف آن خطایی ایجاد نمیکند. علاوه بر این، کامپایلر ویژگیهای اضافی را که در رابط تعریف نشده است، بررسی میکند. برای مثال، اگر پارامتر teslaObj
حاوی نوعی ویژگی اضافی مانند turningCircle
باشد که در رابط TeslaModelS
مشخص نشده است، کامپایلر نوعی خطا ایجاد میکند، مانند مثال زیر:
1buildTeslaModelS({
2 length: 196,
3 width: 86,
4 wheelbase: 116,
5 getTyrePressure: function () {
6 let tyrePressure = 20 // Evaluated after doing a few complex computations!
7 return tyrePressure
8 },
9 getRemCharging: function () {
10 let remCharging = 20 // Evaluated after doing a few complex computations!
11 return remCharging
12 },
13 turningCircle: 10
14})
خطای کامپایلر به صورت زیر است:
Argument of type { length: number; width: number; wheelbase: number; getTyrePressure: () => number; getRemCharging: () => number; turningCircle: number; } is not assignable to parameter of type TeslaModelS. Object literal may only specify known properties, and turningCircle does not exist in type TeslaModelS.
خطای کامپایلر فوق تأکید میکند که ویژگی turningCircle
بخشی از نوع TeslaModelS
نیست و باعث میشود که این ویژگی به رابط مشخصشده پایبند باشد.
ویژگی های فقط خواندنی در رابط ها
در رابطها، ویژگیهای فقط خواندنی آنهایی هستند که پس از مقداردهی اولیه، بدون تغییر باقی میمانند. به عنوان مثال، ویژگیهایی مانند طول، عرض، فاصله بین دو محور و ظرفیت صندلی از ساخت ماشین را در نظر بگیرید که باید مقداری ثابت را در طول چرخه عمر خود حفظ کنند. برای اعمال این تغییرناپذیری، باید رابط را بر این اساس ویژگی فقط خواندنی مانند مثال زیر تنظیم کرد:
1interface TeslaModelS {
2 readonly length: number;
3 readonly width: number;
4 readonly wheelbase: number;
5 readonly seatingCapacity: number;
6 getTyrePressure?: () => number;
7 getRemCharging: () => number;
8}
در مثال بالا، کلمه کلیدی readonly
به ویژگیها اعمال میشود که نشان میدهد این مقادیر پس از اختصاص مقدار اولیه قابل تغییر نیستند. این کار یکپارچگی این ویژگیها را در طول استفاده از رابط تضمین میکند.

ویژگی های قابل ایندکس در اینترفیس
ویژگیهای قابل نمایهسازی یا قابل ایندکس در اینترفیس به نوعی ویژگی اطلاق میشود که با استفاده از اعداد یا رشتههای منحصربهفرد امکان نمایهسازی در آنها را فراهم میکنند. به عنوان مثال، تعریف نوع به نام CustomArray
زیر مدنظر است:
1interface CustomArray { [index: number]: string } let cars: CustomArray = ['Hatchback', 'Sedan', 'Land Rover', 'Tesla Model S'] console.log('Element at position 1', cars[1]) // 'Sedan'
در مثال بالا، نوع CustomArray
امکان نمایهسازی یا همان فهرست بندی با اعداد را فراهم میکند و نوعی تخصصی ایجاد خواهد کرد که از ویژگیها و عملکردهای خاص پشتیبانی میکند و در مواقعی که عملیات سفارشی مورد نیاز است مفید واقع میشود. حال سناریویی عملیتر را بررسی میکنیم. فرض بر این است مجموعهای از خودروهای تسلا مدل S
موجود هستند. میتوان از ویژگیهای قابل ایندکس برای سازماندهی و بررسی کارآمد هر مدل استفاده کرد. رابطهای TeslaModelSMap
و TeslaModelSReview
به صورت زیر برای این هدف معرفی شدهاند:
1interface TeslaModelSMap {
2 engineer: string,
3 model: TeslaModelS,
4 readonly rating: number
5}
6interface TeslaModelSReview {
7 [id: number]: TeslaModelSMap
8}
9
10const TeslaModelSReviewQueue: TeslaModelSReview = [
11 {
12 engineer: 'John',
13 model: modelByJohn1, // modelByJohn1 is of type `TeslaModelS`
14 rating: 2
15 },
16 {
17 engineer: 'Ray',
18 model: modelByRay1, // modelByRay1 is of type `TeslaModelS`
19 rating: 3
20 },
21 {
22 engineer: 'John',
23 model: modelByJohn2, // modelByJohn2 is of type `TeslaModelS`
24 rating: 4
25 },
26 // ... other 97 models
27]
در مثال فوق، رابط TeslaModelSReview
از نوعی اندیس عددی برای مرتبط کردن ویژگیهایی مانند engineer
، model
و rating
با هر مدل تسلا استفاده میکند. این قابلیت امکان سازماندهی کارآمد و بازیابی اطلاعات را در طول فرآیند بررسی فراهم میکند. برای بهبود فرآیند بررسی، اندیسهای TeslaModelSReview
میتوانند فقط خواندنی باشند تا از تغییرات ناخواسته جلوگیری شود. این کار با تنظیم رابط به صورت زیر حاصل میشود:
1interface TeslaModelSReview {
2 readonly [id: number]: TeslaModelS
3}
کد فوق تضمین میکند که تا زمانی که مدلها در حال بررسی هستند، اندیسها تغییرناپذیر باقی میمانند.
نحوه تعریف انواع تابع در اینترفیس
Interface در تایپ اسکریپت همچنین میتواند برای تعریف ساختار توابع استفاده شود. قبلاً، مشاهده کردیم که توابعی مانند getTyrePressure
و getRemCharging
به عنوان ویژگیهایی در رابط TeslaModelS
تعریف شدهاند. با این حال، رویکردی جایگزین برای این کار ایجاد نوعی رابط متمایز به طور خاص برای توابع است.
مثال زیر این مفهوم را بیان میکند:
1interface Order {
2 (customerId: number, modelId: number): boolean
3}
4
5let orderFn: Order = function (cId, mId) {
6 // processing the order
7 return true // processed successfully!
8}
در مثال بالا، رابط Order
ساختار نوعی تابع را مشخص میکند و تعیین خواهد کرد که تابع باید دو پارامتر از نوع عدد (customerId و modelId)
را بپذیرد و مقدار بولی را بازگرداند.
قابل ذکر است، هنگام تعریف تابع orderFn
، دیگر نیازی به اعلام صریح انواع پارامترها نیست. کامپایلر تایپ اسکریپت به طور یکپارچه آرگومانهای موجود در تعریف تابع را با آرگومانهای مشخصشده در رابط مرتبط میکند. این کار شامل نگاشت cId
به customerId
و تعیین انواع مربوطه آنها است که هر دو به عنوان نوع عددی استنتاج میشوند. به طور مشابه، نوع بازگشتی تابع orderFn
به طور خودکار از تعریف رابط استنتاج میشود. این رویکرد ساده، خوانایی و قابلیت نگهداری کد را افزایش میدهد.

نحوه استفاده از اینترفیس با کلاس ها
در این بخش از آموزش Interface در تایپ اسکریپت از مجله فرادرس به بررسی چگونگی استفاده از رابطها با کلاسهای جاوا اسکریپت خواهیم پرداخت. برای نمونه در زیر کلاسی ایجاد شده است که رابط TeslaModelS
را پیادهسازی میکند:
1class TeslaModelSPrototype implements TeslaModelS {
2 length: number;
3 width: number;
4 wheelbase: number;
5 seatingCapacity: number;
6 private tempCache: string;
7
8 constructor(l: number, w: number, wb: number, sc: number) {
9 this.length = l;
10 this.width = w;
11 this.wheelbase = wb;
12 this.seatingCapacity = sc;
13 }
14
15 getTyrePressure() {
16 let tyrePressure = 20 // Evaluated after doing a few complex computations!
17 return tyrePressure
18 }
19
20 getRemCharging() {
21 let remCharging = 20 // Evaluated after doing a few complex computations!
22 return remCharging
23 }
24}
در مثال بالا، کلاس TeslaModelSPrototype
به صراحت ویژگیهای تعریف شده در رابط TeslaModelS
را پیادهسازی میکند. این شامل اعضای خصوصی مانند tempCache
است که بخشی از اینترفیس نیستند و نشان میدهد که رابطها فقط ویژگیهای عمومی کلاس را مشخص میکنند. همچنین برای نمونهسازی شی از این کلاس و استفاده از قابلیتهای آن مثال زیر راداریم:
1let teslaObj = new TeslaModelSPrototype(196, 86, 116, 4);
2console.log('Tyre Pressure', teslaObj.getTyrePressure());
مثال فوق نشان میدهد که چگونه اینترفیسها بهعنوان نقشهای برای ساختارهای کلاس عمل میکنند و اطمینان میدهند که کلاس به واسط مشخصشده پایبند است. ویژگی خصوصی tempCache
بر پایبندی رابط تأثیری نمیگذارد زیرا رابطها فقط بر ویژگیهای عمومی تمرکز میکنند.
انواع مختلف متغیرها در کلاس
در کلاس، سه نوع متمایز از متغیرها وجود دارد که به صورت موارد زیر هستند:
متغیرهای محلی:
- متغیرهای محلی در داخل تابع یا بلوک تعریف میشوند و فقط در طول اجرای آن تابع یا بلوک وجود دارند.
- هر بار که تابع اجرا میشود، نمونههای جدیدی از متغیرهای محلی در حافظه ایجاد میشود.
متغیرهای نمونه:
- متغیرهای نمونه اعضای کلاس هستند و برای ذخیره ویژگیهای اشیای کلاس خدمت میکنند.
- هر شی ایجاد شده از کلاس دارای کپی منحصربهفرد خود از متغیرهای نمونه است.
متغیرهای استاتیک:
- همچنین به عنوان متغیرهای کلاس شناخته میشوند. متغیرهای استاتیک با کل کلاس مرتبط هستند.
- تمام اشیا نمونهسازی شده از کلاس نسخهای از متغیرهای استاتیک را به اشتراک میگذارند.
توجه به این نکته مهم است که هنگام برخورد با اینترفیس در تایپ اسکریپت، تمرکز منحصراً بر روی بخش نمونه کلاس است. به عنوان مثال، تابع سازنده تحت بخش استاتیک قرار میگیرد و در مثال ساخت ماشین تسلا، رابط TeslaModelS
مشخصات سازنده یا هیچ جنبه ایستا کلاس را ارائه نمیدهد.
گسترش اینترفیس در تایپ اسکریپت
رابطها در تایپ اسکریپت میتوانند رابطهای دیگر را گسترش دهند و امکان ترکیب ویژگیهای رابط توسعه یافته را فراهم کنند. این رویکرد باعث ایجاد اجزای کوچک و قابلاستفاده مجدد میشود. مثال زیر را در نظر بگیرید، جایی که رابطهای متمایز اجزای مختلف مدل تسلا را مدیریت میکنند:
1interface Wheel {
2 wheelBase: number;
3 controls: Array<string>,
4 material: string;
5}
6
7interface Charger {
8 adapter: string;
9 connector: string;
10 location: string;
11}
12
13interface TeslaModelS extends Wheel, Charger {
14 // ... All other properties
15}
در مثال فوق، رابط TeslaModelS
هر دو رابط Wheel
و Charger
را گسترش میدهد و ویژگیهای مربوطه را به ارث میبرد. این رویکرد ماژولار تضمین میکند که اجزای مختلف از به وسیله رابطهای جداگانه مدیریت میشوند و سازماندهی کد و قابلیت نگهداری را افزایش میدهد.

نام مستعار نوع چه تفاوتی با رابط ها دارد؟
نام مستعار نوع در تایپ اسکریپت راهی برای اختصاص نامی به ترکیبی از انواع مختلف فراهم میکند. به عنوان مثال، نوع مستعار میتواند برای نشان دادن نوعی داده ایجاد شود که این داده میتواند رشته یا تهی باشد. مانند مثال زیر:
1type StringOrNull = string | null;
نام مستعار نوع و رابط اغلب بهجای یکدیگر استفاده میشوند. برای مثال، ساختار شی TeslaModelS
را میتوان با استفاده از نوع مستعار به صورت زیر تعریف کرد:
1type TeslaModelS {
2 length: number;
3 width: number;
4 wheelbase: number;
5 seatingCapacity: number;
6 getTyrePressure: () => number;
7 getRemCharging: () => number;
8}
مشابه رابطها، نام مستعار نوع میتواند انواع و رابطهای دیگر را با استفاده از عملگر intersection
گسترش دهد. آنها همچنین میتوانند به وسیله نوعی کلاس نیز پیادهسازی شوند. نام مستعار نوع معمولاً هنگام ترکیب انواع مختلف استفاده میشود، همانطور که در مثال تابع renderObject
نشان داده شده است:
1function renderObject (objShape: Square | Rectangle | Triangle) {
2 // ...
3}
در مثال بالا، « Square
»، « Rectangle
» و « Triangle
» انواع هستند و عملگر « |
» به objShape
اجازه میدهد از نوع « Square
»، « Rectangle
» و « Triangle
» باشد. این اتحاد اشکال را نمیتوان با استفاده از اینترفیس بیان کرد.
از سوی دیگر، Interface در تایپ اسکریپت برای تعریف قرارداد در مورد شکل شی مورد استفاده قرار میگیرند. در نتیجه، آنها برای نشان دادن مجموعهای از اشکال چندگانه مناسب نیستند. علاوه بر این، کلاس نمیتواند نوعی را پیادهسازی کند که ترکیبی از اشکال را توصیف میکند و این ویژگی تفاوت عملکردی کلیدی بین رابطها و نامهای مستعار نوع را برجسته میکند. علاوه بر این، اگر دو اینترفیس نامی واحد داشته باشند، در رابط یا اینترفیسی واحد با ویژگیهای هر دو ادغام میشوند. با این حال، تلاش برای تعریف چندین نوع با نام یکسان منجر به خطای کامپایلر میشود.
انواع ترکیبی در رابط ها
در جاوا اسکریپت، توابع به عنوان اشیا در نظر گرفته میشوند و افزودن ویژگیها به توابع مجاز است. این قابلیت معمولاً در الگوهایی مشاهده میشود که تابع به عنوان شی با ویژگیهای اضافی عمل میکند. در تایپ اسکریپت، گرفتن این الگو با استفاده از رابطها شامل ایجاد انواع ترکیبی است که مثال زیر این مفهوم را بیان میکند:
1function manufactureCar (type) {
2 const model = function getModel (type) {
3 console.log('inside getModel function')
4 // get the model of type as mentioned in the argument
5 }
6 model.getCustomerDetails = function () {
7 console.log('inside customer details function')
8 // get the details of the customer who has purchased this model
9 }
10 model.price = 100000
11 model.trackDelivery = function () {
12 console.log('inside trackDelivery function')
13 // track the delivery of the model
14 }
15 return model
16}
17
18let tesla = manufactureCar('tesla')
19tesla() // tesla is a function
20tesla.getCustomerDetails() // getCustomerDetails is a property defined on function
برای بیان این الگو با استفاده از اینترفیس در تایپ اسکریپت، نوع داده ترکیبی به نام CarDelivery
ایجاد میشود که قطعه کد آن به صورت زیر است:
1interface CarDelivery {
2 (string): TeslaModelS,
3 getCustomerDetails (): string,
4 price: number,
5 trackDelivery (): string
6}
7
8function manufactureCar (type: string): CarDelivery {
9 const model = <CarDelivery> function (type: string) {
10 // get the model of type as mentioned in the argument
11 }
12 model.getCustomerDetails = function () {
13 // get the details of the customer who has purchased this model
14 return 'customer details'
15 }
16 model.price = 100000
17 model.trackDelivery = function () {
18 // track the delivery of the model
19 return 'tracking address'
20 }
21 return model
22}
23let tesla = manufactureCar('tesla')
24tesla() // tesla is a function
25tesla.getCustomerDetails() // getCustomerDetails is a property defined on function
تشریح مثال فوق به صورت زیر است:
- رابط CarDelivery
: رابط CarDelivery
برای توصیف ساختار مورد انتظار شی تعریف شده است. این رابط به عنوان نوعی نقشه عمل کرده و ویژگیها و انواع آنها را که یک شی باید داشته باشد را مشخص میکند.
- شی بازگردانی شده به وسیله تابع manufactureCar
: انتظار میرود که تابع manufactureCar
شی را بازگردانی کند که به ساختار مشخص شده به وسیله رابط CarDelivery
متکی است. این شی برای نشان دادن مدلی از یک ماشین در نظر گرفته شده است.
- خواص مشخص شده: رابط CarDelivery
سه ویژگی را مشخص میکند: getCustomerDetails
، price
و trackDelivery
. این ویژگیها رفتار یا ویژگیهای مورد انتظار شی برگشتی را تعریف میکنند.
- نوع هیبریدی یا ترکیبی: شی حاصل از manufactureCar
به عنوان یک نوع ترکیبی توصیف میشود. این بدان معنی است که شی دارای ویژگیهای تابع و مجموعهای از ویژگیها است.
- ویژگیهای قابل فراخوانی: اصطلاح callable
به توانایی شی برای فراخوانی به عنوان تابع، اشاره دارد.
به طور خلاصه، رابط CarDelivery
تضمین میکند که شیای که به وسیله manufactureCar
بازگردانی میشود، از ساختار خاصی پیروی کرده و جنبههای فراخوانی و ویژگیها را در نوعی داده ترکیبی، ادغام میکند.

نحوه استفاده از ژنریک در رابط های تایپ اسکریپت
«Generics» در تایپ اسکریپت راهی برای ایجاد مؤلفههای همهکاره ارائه میدهد که میتوانند بر روی انواع دادههای مختلف کار کنند. به جای محدود کردن تابعی برای پذیرش نوع خاصی از داده، ژنریک به آن اجازه میدهد تا در صورت نیاز با انواع مختلف سازگار شود. بیایید مثالی را با استفاده از اجرای پشته در نظر بگیریم:
1interface StackSpec<T> {
2 (elements: Array<T>): void
3}
4
5function Stack<T> (elements) {
6 this.elements = elements
7 this.head = elements.length - 1
8
9 this.push = function (number): void {
10 this.elements[this.head] = number
11 this.head++
12 }
13
14 this.pop = function <T>(): T {
15 this.elements.splice(-1, 1)
16 this.head--
17 return this.elements[this.head]
18 }
19
20 this.getElements = function (): Array<T> {
21 return this.elements
22 }
23}
24
25let stacksOfStr: StackSpec<string> = Stack
26let cars = new stacksOfStr(['Hatchback', 'Sedan', 'Land Rover'])
27cars.push('Tesla Model S')
28
29console.log('Cars', cars.getElements()) // ['Hatchback', 'Sedan', 'Land Rover', 'Tesla Model S']
در مثال بالا، رابط StackSpec
برای مدیریت هر نوع دادهای طراحی شده است که با نوع عمومی « T
» مشخص میشود. سپس تابع Stack
با قابلیتهای عمومی پیادهسازی شده و به آن اجازه میدهد با آرایهای از عناصر از هر نوع کار کند. متدهای پشته، مانند Push
برای افزودن عنصر و Pop
برای حذف عنصر بالا، برای نوع عمومی « T
» طراحی شدهاند. این انعطافپذیری اجازه میدهد تا از همان پیادهسازی پشته برای انواع دادههای مختلف استفاده مجدد شود که نشاندهنده قدرت ژنریک در ایجاد اجزای سازگار و قابلاستفاده مجدد است.
همچنین در مثال بالا ما با موفقیت پشتهای از رشتهها به نام stacksOfStr
ایجاد کردیم که برای مدیریت رشتهها با جایگزین کردن نوع عمومی « T
» با «رشته» پیکربندی شده است. این قابلیت به ما اجازه میدهد تا از همان پیادهسازی پشته برای انواع دادههای مختلف، مانند اعداد یا هر نوع دیگری، دوباره استفاده کنیم. برای نشان دادن بهتر این موضوع در مثال پایین نوعی پشته که به طور خاص برای مدلهای ماشین تسلای مثالهای بالا طراحی شده است را در نظر بگیریم که قطعه کد آن به صورت زیر است:
1let stacksOfTesla: StackSpec<TeslaModelS> = Stack
2let teslaModels = [
3 {
4 engineer: 'John',
5 modelId: 1,
6 length: 112,
7 //...
8 },
9 // ...
10]
11let teslaStack = new stacksOfTesla(teslaModels)
12console.log(teslaStack) // prints the value of `teslaModels`
در مثال بالا، پشتهای به نام teslaStack
با استفاده از Stack
با نوع عمومی که روی TeslaModelS
تنظیم شده، نمونهسازی شده است. این پشته به کاربر اجازه میدهد تا آرایهای از اشیا مدل تسلا را مدیریت کند. توجه به این نکته مهم است که همان پیادهسازی پشته به طور یکپارچه برای مدیریت آرایه از نوع خاص اعمال میشود و اثربخشی ترکیب ژنریکها با رابطها در تایپ اسکریپت را نشان میدهد. این ترکیب قدرتمند امکان ایجاد اجزای انعطافپذیر و قابلاستفاده مجدد را فراهم میکند که میتوانند با انواع دادهها سازگار شوند.
نحوه کامپایل کردن اینترفیس در تایپ اسکریپت چگونه است؟
تایپ اسکریپت، اگرچه در مدیریت پیچیدگیهای جاوا اسکریپت بسیار خوب عمل میکند اما در اجرای مرورگر با نوعی چالش مواجه است زیرا مرورگرها ذاتاً جاوا اسکریپت را درک میکنند نه تایپ اسکریپت. بنابراین، کد تایپ اسکریپت باید در جاوا اسکریپت کامپایل شود.
کامپایلر تایپ اسکریپت کلاس TeslaModelSPrototype
ارائه شده را به کد جاوا اسکریپت زیر تبدیل میکند که مثال زیر برای بیان این هدف است:
1var TeslaModelSPrototype = (function () {
2 function TeslaModelSPrototype(l, w, wb, sc) {
3 this.length = l;
4 this.width = w;
5 this.wheelbase = wb;
6 this.seatingCapacity = sc;
7 }
8 TeslaModelSPrototype.prototype.getTyrePressure = function () {
9 var tyrePressure = 20; // Evaluated after doing a few complex computations!
10 return tyrePressure;
11 };
12 TeslaModelSPrototype.prototype.getRemCharging = function () {
13 var remCharging = 20; // Evaluated after doing a few complex computations!
14 return remCharging;
15 };
16 return TeslaModelSPrototype;
17}());
18var teslaObj = new TeslaModelSPrototype(196, 86, 116, 4);
19console.log('Tyre Pressure', teslaObj.getTyrePressure());
در مثال بالا، متغیرهای نمونه مانند « length
»، « width
»، « wheelbase
» و « seatingCapacity
» در تابع « TeslaModelSPrototype
» مقداردهی اولیه میشوند. در همین حال، متدهای getTyrePressure
و getRemCharging
بر روی نمونه اولیه تابع TeslaModelSPrototype
تعریف شدهاند. این کد بهدست آمده جاوا اسکریپت کدی استاندارد است و میتواند به طور یکپارچه در محیط مرورگر اجرا شود.
دلایل استفاده از اینترفیس در تایپ اسکریپت چیست؟
اینترفیسها به کارایی موتورهای جاوا اسکریپت کمک میکنند. برای بررسی این موضوع، بیایید کارکردهای داخلی موتورهای جاوا اسکریپت را با تمرکز بر «V8»، موتور مورد استفاده کروم، بررسی کنیم. وقتی صحبت از ذخیره اشیا میشود، Interface در تایپ اسکریپت فقط در زمان کامپایل نقش دارند. بررسی کد تولید شده به وسیله کامپایلر تایپ اسکریپت عدم وجود رابط را آشکار میکند. در عوض، ویژگیهای رابط TeslaModelS
جای خود را در سازنده TeslaModelSPrototype
پیدا میکنند. به طور همزمان، انواع تابع به نمونه اولیه تابع TeslaModelSPrototype
اضافه میشود. نکته مهم این است که موتورهای جاوا اسکریپت از رابطها غافل هستند.
برای درک بهتر این موضوع سناریوی ایجاد خودروهای متعدد TeslaModelSPrototype
مد نظر است. با وجود اینکه هر شی از نوع TeslaModelS
است، موتور جاوا اسکریپت چندین کپی از ساختار رابط برای هر شی تولید نمیکند. در عوض، برای اشیایی از نوع TeslaModelS
نوعی شکل منفرد ایجاد میکند و هر شی به سادگی مقادیر ویژگیهای مربوطه را ذخیره کرده و با رابط TeslaModelS
همسو میشود.

این رویکرد دارای مزیت عملکرد قابلتوجهی برای موتورهای جاوا اسکریپت است. این موتور به جای کپی کردن اشکال مشابه برای هزاران شی، استفاده از حافظه را با حفظ نوعی شکل یکپارچه برای اشیای متصل به رابط TeslaModelS
بهینه میکند. در مواردی که اشیاء دارای اشکال متمایز هستند، موتور مجبور است برای هر شی اشکال متفاوتی ایجاد و آن را مدیریت کند. اینترفیس در جاوا اسکریپت نقشی اساسی در حفظ یکنواختی اشکال برای اشیا با ویژگیهای مشترک دارد و به بهبود عملکرد کمک میکند.
اینترفیس های قابل فراخوانی در تایپ اسکریپت
اینترفیسهای قابل فراخوانی مکانیزمی را در تایپ اسکریپت فراهم میکنند تا از استفاده صحیح از توابع با ثبت مسائل احتمالی مربوط به آرگومانهای نادرست یا مقادیر برگشتی اطمینان حاصل کند. مثال زیر در این رابطه مهم است:
1const generateANumber: Function = (factor: number, genFunc: Function) => {
2return genFunc(factor)
3}
4console.log(generateANumber(5, (a:number) => a)) // 5
5console.log(generateANumber(5, () => "Cheese")) //Cheese
در کد بالا، نوعی مشکل احتمالی وجود دارد. ما قصد داریم که genFunc
تابعی باشد که عددی را میگیرد و عددی را بازمیگرداند اما تنظیمات فعلی این قانون را اجرا نمیکند. برای مثال، ارسال تابعی که هیچ آرگومان نمیگیرد و رشتهای را بازمیگرداند، هیچ نوع خطای ایجاد نمیکند. برای پرداختن به این مشکل، میتوان از رابطهای قابل فراخوانی برای تعریف تابع مورد انتظار استفاده کرد که مثال زیر این موضوع را بیان میکند:
1// Callable Interface
2interface NumberGenerator {
3 (num: number): number
4}
5interface GenANum {
6 (num: number, gen: NumberGenerator): number
7}
8const generateANumber: GenANum = (factor: number, genFunc: NumberGenerator) => {
9 return genFunc(factor)
10}
11console.log(generateANumber(5, (a:number) => a)) // 5
12console.log(generateANumber(5, () => "Cheese")) // Type Error
اکنون با معرفی اینترفیسها (« NumberGenerator
» و « GenANum
»)، به صراحت تعریف تابع « generateANumber
» و آرگومان « genFunc
» آن قابل انجام هستند. اگر تابع نادرست ارسال شود، مانند () => “Cheese”
، خطای نوع را دریافت میکند و ایمنی نوع کلی کد را افزایش میدهد. اینترفیسهای قابل فراخوانی نقش مهمی در اطمینان از تعیین صحیح توابع دارند.
نحوه استفاده از رابط ها با React
بیایید مثالی ساده از استفاده از رابطهای React و تایپ اسکریپت برای نمایش فهرستی از Pokemon
ایجاد کنیم. مؤلفه اصلی App
، یک PokemonList
را در کانتینر div
که به وسیله شناسه ریشه شناسایی شده است، ارائه میکند:
1import React, { Fragment } from 'react';
2import { render } from 'react-dom';
3import PokemonList from './pokemon-list';
4import './style.css';
5
6const App = () => {
7 return (
8 <Fragment>
9 <h2>Pokemon List</h2>
10 <PokemonList />
11 </Fragment>
12 )
13}
14
15render(<App />, document.getElementById('root'));
در تنظیمات بالا، مؤلفه App
منطق رندر PokemonList
را کپسوله میکند. اجرای مؤلفه PokemonList
به صورت زیر است:
1import React, { Component } from 'react';
2import { PokemonListModel } from './pokemon-model';
3
4interface PokemonProps {}
5interface PokemonState {
6 pokemonList: PokemonListModel | null;
7}
8
9class PokemonList extends Component<PokemonProps, PokemonState> {
10
11 constructor (props) {
12 super(props);
13 this.state = {
14 pokemonList: null
15 }
16 }
17
18 getPokemonList = () => {
19 fetch ('https://pokeapi.co/api/v2/pokemon/?limit=50')
20 .then (response => {
21 return response.json();
22 })
23 .then (response => {
24 this.setState({ pokemonList: response });
25 })
26 }
27
28 render () {
29 let { pokemonList } = this.state;
30 return (
31 <div className='pokemon-list'>
32 {
33 pokemonList && pokemonList.results.map (pokemon => {
34 return (
35 <div className='row' key={pokemon.name}>
36 <span>{pokemon.name}</span>
37 </div>
38 )
39 })
40 }
41 </div>
42 )
43 }
44
45 componentDidMount () {
46 this.getPokemonList()
47 }
48}
49
50export default PokemonList
کامپوننت PokemonList
لیستی از Pokemon
را از API منبع باز Pokemon
بازیابی کرده و نتایج API را در وضعیت کامپوننت ذخیره میکند. این کامپوننت از رابطهای PokemonProps
و PokemonState
برای تعریف ویژگیها و وضعیت خود استفاده میکند. همچنین رابط PokemonListModel
ساختار شی را که از API Pokemon
بازگردانی شده است را ترسیم خواهد کرد. حال نوبت به بررسی رابط PokemonListModel
بوده که قطعه کد آن به صورت زیر است:
1export interface PokemonListModel {
2 count: number;
3 next: string | null;
4 previous: string | null;
5 results: Array
6}
7
8interface Pokemon {
9 name: string;
10 url: string;
11}
در رابط فوق، ویژگی results
از نوع « Array«Pokemon»
» است که در آن Pokemon
رابط دیگری محسوب میشود که ساختار تک تک اشیا Pokemon
را تعریف میکند. نمایشی از برنامه Pokemon
به صورت تصویر زیر است:

استفاده از رابط ها در Angular
در این بخش از آموزش Interface در تایپ اسکریپت به بررسی قابلیت استفاده از اینترفیسها با «انگولار» (Angular) خواهیم پرداخت. در Angular که بر اساس تایپ اسکریپت ساخته شده است، اینترفیسها نقش مهمی دارند. بررسی پایگاه کد زیر برای درک نحوه رفتار این اینترفیسها در انگولار خالی از لطف نیست.
1export interface Post {
2 title: string
3 content: string
4}
در مثال بالا ابتدا محتوای فایل /src/app/types.ts
مد نظر است. این فایل به عنوان نوعی مکان مرکزی برای تعریف اینترفیسها و انواعی که در سراسر برنامه مورد استفاده قرار میگیرد عمل میکند: در این مثال، رابطی به نام Post
وجود دارد که دو ویژگی title
و content
را مشخص میکند. هدف تسهیل بازیابی و افزودن پستها در برنامه است.
برای درک بهتر کار اینترفیسها در تایپ اسکریپت کپسولهسازی مدیریت داده در فایل /src/app/post.service.ts
مورد بررسی واقع خواهد شد که کد زیر برای این هدف مد نظر است:
1import { Injectable } from '@angular/core';
2import { Post } from './types';
3
4@Injectable({
5 providedIn: 'root'
6})
7export class PostService {
8 private posts: [Post]; // Private property representing an array of posts
9
10 constructor() {
11 this.posts = [{ title: "Post 0", content: "content for post 0" }];
12 }
13
14 // Method for adding a post
15 addPosts(newPost: Post) {
16 this.posts.push(newPost);
17 }
18
19 // Method for getting all posts
20 getPosts() {
21 return this.posts;
22 }
23}
در کد فوق، از رابط Post
برای تعریف ویژگی خصوصی، که آرایهای از پستها است، استفاده خواهد شد. آرایه با پست اولیه مقداردهی اولیه میشود. این سرویس دو متد زیر را ارائه میدهد:
- addPosts
: پستی را به عنوان آرگومان میپذیرد و آن را به آرایه “this.posts”
اضافه میکند.
- getPosts
: آرایه حاوی اشیا Post
را بازمیگرداند.

میتوان در برنامه Angular بالا از نوعی سرویس ویژه به نام PostService
، برای مدیریت فهرستی از پستها استفاده میشود. کلاس AppComponent
که مسئول کامپوننت اصلی برنامه است، PostService
را برای دسترسی به تابعهایی که ارائه میدهد، تزریق میکند. قطعه کد انجام این کار به صورت زیر است:
1import { Component } from '@angular/core';
2import { PostService } from './post.service';
3import { Post } from './types';
4@Component({
5 selector: 'app-root',
6 templateUrl: './app.component.html',
7 styleUrls: ['./app.component.css'],
8})
9export class AppComponent {
10 title = 'sampleproject';
11 postService: PostService;
12 posts: [Post]
13 // initiate PostService in component
14 constructor(postService: PostService) {
15 this.postService = postService;
16 this.posts = this.postService.getPosts()
17 }
18 addPost() {
19 // Create new post
20 const newPost: Post = {
21 title: `Post ${this.posts.length}`,
22 content: 'this is the content for this post',
23 };
24 // update list of posts in service and component
25 this.postService.addPosts(newPost)
26 this.posts = this.postService.getPosts()
27 }
28}
در AppComponent
، دو ویژگی کلیدی وجود دارد:
- postService
: این ویژگی نمونهای از postService
را که قبلاً تعریف شده است، نشان میدهد و به عنوان پلی بین کامپوننت و سرویس مدیریت داده عمل میکند.
- posts
: این ویژگی آرایهای از اشیا Post
را به صورت محلی در کامپوننت نگه میدارد. این ویژگی به عنوان یک کپی از فهرست پستهای بازیابی شده از سرویس عمل میکند.
سازنده کامپوننت از تزریق وابستگی برای مقداردهی اولیه نمونه postService
استفاده میکند. علاوه بر این، فهرست اولیه پستها را با استفاده از متد getPosts
از سرویس دریافت کرده و ویژگی پستهای محلی را پر میکند. برای تسهیل افزودن پستهای جدید، کامپوننت شامل متد addPost
است. این متد پست جدیدی با عنوان تولید شده به صورت پویا و محتوای از پیش تعریف شده ایجاد میکند. سپس پست به وسیله متد addPost
سرویس به لیست اضافه شده و بر این اساس ویژگی پست محلی بهروز میشود.
همچنین میتوان متد addPost
محلی در کامپوننت معرفی شود که امکان افزودن پستهای جدید به وسیله برنامه را فراهم میکند و در عین حال همگامسازی را با سرویس و آرایه محلی تضمین خواهد کرد. برای ارائه نوعی رابط کاربری برای این تابع، ظاهر کامپوننت را در فایل src/app/app.component.html
تعریف میکنیم.
1<h1> Posts </h1>
2<button (click)="addPost()">Add Post</button>
3<div *ngFor="let post of posts; index as i">
4 <h2>{{post.title}}</h2>
5 <p>{{post.content}}</p>
6</div>
قالب HTML شامل موارد زیر است:
- عنصر h1
که عنوان پستها را نمایش میدهد.
- button
که پس از کلیک کردن، متد addPost
را فعال کرده و افزودن پستی جدید را تسهیل میکند.
عنصر div
که از دستور Angular *ngFor
برای پیمایش روی آرایههای Posts
از کامپوننت استفاده میکند، برای هر پست، نوعی عنصر h2
برای عنوان و نوعی عنصر p
برای محتوا ایجاد میکند.
در طول این فرآیند، رابط پست نقش مهمی ایفا میکند. استفاده از آن تضمین میکند که هرگونه خطا، مانند غلط املایی در زمان کامپایلر گرفته میشود و از خطاهای احتمالی زمان اجرا در برنامه جلوگیری میکند. این رویکرد استحکام و قابلیت اطمینان کلی پایگاه کد را افزایش میدهد.
نکاتی در رابطه با Interface در تایپ اسکریپت
Interface در تایپ اسکریپت به عنوان نوعی مکانیسم قوی برای ایجاد قرارداد در تایپ اسکریپت عمل میکنند. توجه به نکات زیر در رابطه با Interfaceها بسیار حائز اهمیت است:
- مشخصات موجودیتها: رابطها مشخصات موجودیتها را مشخص میکنند و اینها میتوانند به وسیله توابع و کلاسها پیادهسازی شوند. ویژگیهای اختیاری را میتوان با ?
نشان داد، در حالی که ویژگیهای فقط خواندنی از کلمه کلیدی فقط خواندنی در نام ویژگی استفاده میکنند.
- بررسیهای کامپایلر: کامپایلر تایپ اسکریپت بررسیهایی را برای ویژگیهای اضافی روی اشیا انجام میدهد و در صورتی که شی حاوی خصوصیتی باشد که در رابط تعریف نشده باشد، خطا ایجاد میکند.
- ویژگیهای قابل ایندکس: چگونگی تعریف ویژگیهای قابل ایندکس را با استفاده از رابطها بررسی میکند.
- پیادهسازی کلاس: کلاسها توانایی پیادهسازی رابطها را دارند.
- گسترش رابط: رابطها را میتوان گسترش داد و امکان وارد کردن ویژگیها از سایر رابطها را با استفاده از کلمه کلیدی extends
فراهم میکند.
- استفاده از Generics: قدرت ژنریکها در تایپ اسکریپت را میتوان با رابطها مهار کرد و ایجاد اجزای قابلاستفاده مجدد را تسهیل کرد.
- قابلیت ذخیرهسازی بهینه: رابطها با کمک به ذخیرهسازی کارآمد اشیا با اشکال مشابه، به عملکرد موتورهای جاوا اسکریپت کمک میکنند.
این مفاهیم در مجموع تطبیقپذیری و کاربرد رابطها در تایپ اسکریپت را نشان داده و مجموعه ابزار جامعی را برای ایجاد کدهای قوی و قابل نگهداری ارائه میدهند.
سخن پایانی
Interface در تایپ اسکریپت به عنوان سنگ بنای تعریف قراردادهای واضح کدنویسی، بهبود ساختار کد و ارتقای بررسی نوع قوی عمل میکند. اینترفیس به توسعهدهندگان اجازه میدهد تا شکل مورد انتظار اشیا، توابع و کلاسها را مشخص کنند. همچنین این قابلیت در تایپ اسکریپت همکاری یکپارچه را در پایگاه کد تسهیل کرده و تشخیص خطاهای احتمالی را در طول توسعه به جای زمان اجرا امکان پذیر میسازد. یکی از مزایای قابل توجه رابطها تأثیر مثبت آنها بر عملکرد موتور جاوا اسکریپت است. با بهینهسازی ذخیرهسازی اشیا با اشکال مشابه، رابطها به کارایی حافظه و سرعت کلی زمان اجرا کمک میکنند.
در مطلب فوق از مجله فرادرس مفهوم اینترفیسها در جاوا اسکریپت مورد بررسی قرار گرفت و در سناریوهای عملی متفاوتی، استفاده از اینتفریس مورد بازبینی قرار گرفت. همچنن مباحثی مانند تعیین نوع اردکی، تفاوت اینترفیس و انواع در تایپ اسکریپت، انواع تابع در اینترفیس، گسترش اینترفیس در تایپ اسکریپت، اینترفیسهای قابل فراخوانی در تایپ اسکریپت، نحوه استفاده از رابطها با React و استفاده از رابطها در Angular مورد بررسی قرار گرفتند.
source