استفاده از interface و کلاس در تایپ اسکریپت

دو مفهوم interface و کلاس جزء مفاهیم اساسی برنامه نویسی شی‌گرا (OOP) هستند. تایپ اسکریپت یک زبان جاوااسکریپتی شی‌گرا است که از ES6 به بعد از ویژگی‌های OOP مانند interface، کلاس و کپسوله‌سازی پشتیبانی می‌کند.

سوالی که ممکن است مطرح شود این است که چه زمانی باید از interfaceها، کلاس‌ها و یا هر دو به طور همزمان استفاده کنیم؟ در این مقاله قصد داریم تا با انواع interface و کلاس آشنا شویم و یاد بگیریم که چه زمانی باید از یک یا هر دوی آن‌ها در تایپ اسکریپت استفاده کنیم.

منظور از کلاس در تایپ اسکریپت چیست؟

قبل از شروع، باید بدانیم کلاس تایپ اسکریپت چیست. در برنامه نویسی شی‌گرا، کلاس یک طرح یا قالب است که به وسیله آن می‌توانیم آبجکت‌هایی با ویژگی‌ها و متدهای خاص ایجاد کنیم.

تایپ اسکریپت سینتکس اضافی برای بررسی تایپ را ارائه می‌کند و کد را به جاوااسکریپتی که روی هر پلتفرم و مرورگری اجرا می‌شود تبدیل می‌نماید. کلاس‌ها در تمامی مراحل دخالت دارند. پس از تبدیل کد تایپ اسکریپت به یک فایل جاوااسکریپت، می‌توانیم آن‌ها را در فایل‌های نهایی پیدا کنیم.

کلاس الگوی آبجکت را تعریف می‌کند، یا اینکه آبجکت چیست و چه کاری انجام می‌دهد را تعیین می‌کند. در ادامه یک کلاس ساده با یک سری ویژگی‌ها و متدها ایجاد می‌کنیم تا بتوانیم رفتار آن را ببینیم.

ابتدا از طریق کد زیر یک کلاس

Developer
Developerایجاد می‌کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Developer {
name?: string; // string or undefined
position?: string; // string or undefined
}
class Developer { name?: string; // string or undefined position?: string; // string or undefined }
class Developer {
  name?: string; // string or undefined
  position?: string; // string or undefined
}

ما کلاس را با ویژگی‌های

name
nameو
position
positionتوصیف می‌کنیم. آن‌ها تایپ‌هایی مانند
string
stringو
undefined
undefinedدارند.

در مرحله بعد، از طریق کلاس

Developer
Developerو با استفاده از کلمه کلیدی
new
newیک آبجکت ایجاد می‌کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const developer = new Developer();
developer.name // it outputs undefined
developer.position // it outputs undefined
const developer = new Developer(); developer.name // it outputs undefined developer.position // it outputs undefined
const developer = new Developer();
developer.name // it outputs undefined
developer.position // it outputs undefined

هنگامی که

developer.name
developer.nameرا فراخوانی می‌کنیم، مقدار
undefined
undefinedرا برمی‌گرداند زیرا مقادیر اولیه را تعیین نکرده‌ایم. برای ایجاد یک آبجکت با مقادیر اولیه در تایپ اسکریپت می‌توانیم از متد constructor استفاده کنیم. متد constructor برای مقداردهی اولیه و ایجاد آبجکت‌ها استفاده می‌شود.

اکنون کلاس

Developer
Developerخود را با استفاده از کد زیر به روز رسانی می‌کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Developer {
name: string; // only string
position: string; // only string
constructor(name: string, position: string) {
this.name = name;
this.position = position;
}
}
class Developer { name: string; // only string position: string; // only string constructor(name: string, position: string) { this.name = name; this.position = position; } }
class Developer {
  name: string; // only string
  position: string; // only string

  constructor(name: string, position: string) {
    this.name = name;
    this.position = position;
  }
}

در کد بالا، متد

constructor
constructorرا برای مقداردهی اولیه ویژگی‌ها اضافه کردیم.

اکنون می‌توانیم با استفاده از کد زیر

name
nameرا به عنوان
Gapur
Gapurو
position
positionرا به عنوان
Frontend Developer
Frontend Developerتنظیم کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const developer = new Developer("Gapur", "Frontend Developer");
developer.name // it outputs Gapur
developer.position // it outputs Frontend Developer
const developer = new Developer("Gapur", "Frontend Developer"); developer.name // it outputs Gapur developer.position // it outputs Frontend Developer
const developer = new Developer("Gapur", "Frontend Developer");
developer.name // it outputs Gapur
developer.position // it outputs Frontend Developer

در نهایت، همانطور که قبلاً هم اشاره کردیم، کلاس متدهایی دارد که تعیین می‌کند آبجت چگونه باید عمل کند. در این حالت، هر developerای برنامه‌هایی را develop می‌کند. بنابراین، کلاس

Developer
Developerدارای متد
develop
developاست.

یک آبجکت

developer
developerمی‌تواند یک اکشن develop را انجام دهد:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Developer {
name: string;
position: string;
constructor(name: string, position: string) {
this.name = name;
this.position = position;
}
develop(): void {
console.log('develop an app');
}
}
class Developer { name: string; position: string; constructor(name: string, position: string) { this.name = name; this.position = position; } develop(): void { console.log('develop an app'); } }
class Developer {
  name: string;
  position: string;

  constructor(name: string, position: string) {
    this.name = name;
    this.position = position;
  }

  develop(): void {
    console.log('develop an app');
  }
}

اگر متد

develop
developرا اجرا کنیم، عبارت
console.log
console.logزیر را اجرا می‌کند:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
developer.develop() // it outputs develop an app
developer.develop() // it outputs develop an app
developer.develop() // it outputs develop an app

منظور از interface در تایپ اسکریپت چیست؟

interface در تایپ اسکریپت ساختاری است که مانند یک قرارداد در برنامه و یا سینتکسی برای کلاس عمل می‌کند. interface همچنین به عنوان duck printing و یا subtyping نیز شناخته می‌شود.

interface شامل یک متد

only
onlyو تعریف‌های فیلد بدون پیاده‌سازی می‌باشد. ما نمی‌توانیم از آن برای ایجاد چیزی استفاده کنیم. کلاسی که یک interface را پیاده‎‌سازی می‌کند باید تمام فیلدها و متدها را داشته باشد. بنابراین، ما آن را برای بررسی تایپ به کار می‌گیریم.

هنگامی که تایپ اسکریپت تمام کدها را به جاوااسکریپت تبدیل می‌کند، interface از فایل جاوااسکریپت محو می‌شود. بنابراین، ابزار مفیدی در فار توسعه به شمار می‌آید.

ما باید از یک interface برای موارد زیر استفاده کنیم:

  • اعتبارسنجی ساختار خاص ویژگی‌ها
  • آبجکت‌ها به عنوان پارامترها
  • آبجکت‌های return شده از توابع

اکنون می‌خواهیم با کمک کد زیر یک interface تعریف کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface InterfaceName {
// variables;
// methods;
}
interface InterfaceName { // variables; // methods; }
interface InterfaceName {
  // variables;
  // methods;
}

ما فقط می‌توانیم تعریف‌هایی از متغیرها و متدها را در بدنه interface داشته باشیم. در ادامه می‌خواهیم یک interface

IDeveloper
IDeveloperبرای کلاس
Developer
Developerقبلی ایجاد کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface IDeveloper {
name: string
position: string
develop: () => void
}
class Developer implements IDeveloper {
name: string;
position: string;
constructor(name: string, position: string) {
this.name = name;
this.position = position;
}
develop(): void {
console.log('develop an app');
}
}
interface IDeveloper { name: string position: string develop: () => void } class Developer implements IDeveloper { name: string; position: string; constructor(name: string, position: string) { this.name = name; this.position = position; } develop(): void { console.log('develop an app'); } }
interface IDeveloper {
  name: string
  position: string
  develop: () => void
}

class Developer implements IDeveloper {
  name: string;
  position: string;

  constructor(name: string, position: string) {
    this.name = name;
    this.position = position;
  }

  develop(): void {
    console.log('develop an app');
  }
}

در کد بالا، interface

IDeveloper
IDeveloperما شامل
name
nameو
position
positionمتغیرها است. همچنین متد
develop
developرا هم شامل می‌شود. در نتیجه کلاس
Developer
Developerinterface
IDveloper
IDveloperرا پیاده سازی می‌کند. بنابراین، باید دو متغیر و یک متد تعریف کند.

اگر کلاس

Developer
Developerهیچ متغیری را پیاده سازی نکند، تایپ اسکریپت یک خطا نشان می‌دهد:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Developer implements IDeveloper {
// error Class 'Developer' incorrectly implements interface 'IDeveloper'.
name: string;
constructor(name: string, position: string) {
this.name = name;
this.position = position;
}
develop(): void {
console.log('develop an app');
}
}
class Developer implements IDeveloper { // error Class 'Developer' incorrectly implements interface 'IDeveloper'. name: string; constructor(name: string, position: string) { this.name = name; this.position = position; } develop(): void { console.log('develop an app'); } }
class Developer implements IDeveloper {
  // error Class 'Developer' incorrectly implements interface 'IDeveloper'.
  name: string;

  constructor(name: string, position: string) {
    this.name = name;
    this.position = position;
  }

  develop(): void {
    console.log('develop an app');
  }
}

تفاوت بین Interfaceها و کلاس‌ها

اکنون سوالی که مطرح می‌شود این است که در تایپ اسکریپت چه زمانی باید از کلاس و چه زمانی از interface استفاده کنیم؟

قبل از پاسخ به این سوال می‌خواهیم در مورد ویژگی

static
staticتایپ اسکریپت صحبت کنیم که به ما این امکان را می‌دهد تا از فیلدها و متدهای کلاس‌ها بدون ایجاد نمونه کلاس استفاده کنیم.

اکنون قصد داریم تا با استفاده از کلاس

Developer
Developerقبلی یک کلاس با متد static بسازیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Developer {
static develop(app: { name: string, type: string }) {
return { name: app.name, type: app.type };
}
}
class Developer { static develop(app: { name: string, type: string }) { return { name: app.name, type: app.type }; } }
class Developer {
  static develop(app: { name: string, type: string }) {
    return { name: app.name, type: app.type };
  }
}

اکنون می‌توانیم متد

Developer.develop()
Developer.develop()را بدون نمونه‌سازی کلاس فراخوانی کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Developer.develop({ name: 'whatsapp', type: 'mobile' })
// outputs: { "name": "whatsapp", "type": "mobile" }
Developer.develop({ name: 'whatsapp', type: 'mobile' }) // outputs: { "name": "whatsapp", "type": "mobile" }
Developer.develop({ name: 'whatsapp', type: 'mobile' })
// outputs: { "name": "whatsapp", "type": "mobile" }

همچنین می‌توانیم از کلاس‌ها برای بررسی تایپ در تایپ اسکریپت استفاده کنیم. در ادامه با استفاده از کد زیر یک کلاس

App
Appایجاد می‌کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class App {
name: string;
type: string;
constructor(name: string, type: string) {
this.name = name;
this.type = type;
}
}
class App { name: string; type: string; constructor(name: string, type: string) { this.name = name; this.type = type; } }
class App {
  name: string;
  type: string;

  constructor(name: string, type: string) {
    this.name = name;
    this.type = type;
  }
}

کلاس

Developer
Developerخود را تغییر می‌دهیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Developer {
static develop(app: App) {
return { name: app.name, type: app.type }; // output the same
}
}
class Developer { static develop(app: App) { return { name: app.name, type: app.type }; // output the same } }
class Developer {
  static develop(app: App) {
    return { name: app.name, type: app.type }; // output the same
  }
}

اکنون یک نمونه از

App
Appرا می‌سازیم و
Developer.develop()
Developer.develop()را با یک argument object فراخوانی می‌کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const app = new App('whatsapp', 'mobile');
Developer.develop(app);
// outputs the same: { "name": "whatsapp", "type": "mobile" }
const app = new App('whatsapp', 'mobile'); Developer.develop(app); // outputs the same: { "name": "whatsapp", "type": "mobile" }
const app = new App('whatsapp', 'mobile');
Developer.develop(app);
// outputs the same: { "name": "whatsapp", "type": "mobile" }

Developer.develop(app)
Developer.develop(app)و
Developer.develop({ name: 'whatsapp', type: 'mobile' })
Developer.develop({ name: 'whatsapp', type: 'mobile' })هر دو محتوای یکسانی را تولید می‌کنند. اما رویکرد دوم خواناتر است و انعطاف‌پذیری بیشتری دارد.

علاوه بر این می‌توانیم نوع آرگومان‌ها را هم بررسی کنیم. برای انجام این کار باید یک آبجکت ایجاد کنیم. اینجاست که مفهوم interfaceها مطرح می‌شود.

ابتدا می‌خواهیم کلاس

App
Appرا با استفاد از کد زیر به یک interface تغییر دهیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface App {
name: string
type: string
}
class Developer {
static develop(app: App) {
return { name: app.name, type: app.type }; // output the same
}
}
interface App { name: string type: string } class Developer { static develop(app: App) { return { name: app.name, type: app.type }; // output the same } }
interface App {
  name: string
  type: string
}

class Developer {
  static develop(app: App) {
    return { name: app.name, type: app.type }; // output the same
  }
}

در کد بالا، بدنه کلاس

Developer
Developerرا تغییر ندادیم و نمونه‌ای از
App
Appایجاد نکردیم، اما نتیجه یکسان بود. همینطور زمان کوتاه‌تر بوده و تعداد خط کد نیز کم‌تر از قبل می‌باشد.

جمع‌بندی

چه زمانی باید از کلاس‌ها و interfaceها استفاده کنیم؟ به طور خلاصه اگر می‌خواهیم یک type-checked class object ایجاد و ارسال کنیم، باید از کلاس‌های تایپ اسکریپت استفاده کنیم. اما اگر نیاز داریم بدون ایجاد آبجت کار کنیم، استفاده از interfaceها بهترین انتخاب است.

در نهایت، ما دو رویکرد مفید blueprint و contract را بررسی کردیم که می‌توانیم بسته به شرایط پروژه از هر دوی آن‌ها باهم و یا به صورت جداگانه استفاده کنیم.

دیدگاه‌ها:

افزودن دیدگاه جدید