راهنمای جامع TypeScript؛ تفاوت Type و Interface چیست و چه زمانی از کدام استفاده کنیم؟
اگر به تازگی وارد دنیای TypeScript شدید یا حتی مدتیه که از اون تو پروژههاتون (مثل Next.js یا React) استفاده میکنید، احتمالاً این سوال برای شما هم پیش اومده: «بالاخره برای تعریف ساختار دادهها از type استفاده کنم یا interface؟»
در نگاه اول، این دو کلمه کلیدی شباهتهای زیادی به هم دارن و در اکثر مواقع کار یکسانی رو انجام میدن. اما در لایههای پایینتر، تفاوتهای ساختاری و عملکردی مهمی دارن که شناخت اونها، قطعا تو پروژه کمک کنندهست.
در این مقاله میخوایم این تفاوتها رو موشکافی کنیم و ببینیم در سناریوهای واقعی، کدومیک انتخاب بهتریه.
شباهتها:
قبل از اینکه سراغ تفاوتها بریم، بهتره بدونیم که هر دو ابزار میتونن شکل یک شیء (Object) رو به راحتی توصیف کنن و هر دو از قابلیتهایی مثل ارثبری پشتیبانی میکنن:
// تعریف یک شیء با استفاده از Interface
interface UserInterface {
id: number;
name: string;
}
// تعریف همان شیء با استفاده از Type
type UserType = {
id: number;
name: string;
};
تفاوتها: چرا به هر دو نیاز داریم؟
۱. قابلیت ادغام خودکار یا Declaration Merging (کدوم بهتره: Interface)
بزرگترین و مهمترین تفاوت ساختاری این دو اینه که
interfaceها باز (Open) هستن، اما typeها بسته (Closed). یعنی شما میتونید یک interface رو چند بار با یک نام یکسان تعریف کنید و TypeScript به صورت خودکار تمام فیلدهای اونها رو با هم ادغام میکنه:interface Client {
name: string;
}
interface Client {
age: number;
}
// ادغام خودکار: حالا کلاینت هر دو فیلد را دارد
const newClient: Client = {
name: "Ali",
age: 25
};
type انجام بدید، بلافاصله با خطای دیتای تکراری (Duplicate identifier) مواجه میشد. این ویژگیِ interface برای زمانهایی که میخواید برای یک کتابخانه اکسترنال (مثل اضافه کردن فیلد به درخواستهای Express یا تنظیمات تلویند) متغیر جدیدی اضافه کنید، حیاتیه.۲. انواع دادههای غیر شیء یا Primitive Types (کدوم بهتره: Type)
یک
interface فقط و فقط میتونه شکل یک شیء (Object) یا تابع (Function) رو مشخص کنه. اما کلمه کلیدی type بسیار انعطافپذیرتره و میتونه برای تعریف انواع الیاسها (Aliases)، تایپهای ترکیبی (Union) یا چندوجهی (Intersection) استفاده شه:// Union Types (تعریف تایپی که میتواند یکی از چند حالت باشد)
type Status = "pending" | "approved" | "rejected";
type ID = string | number;
// Tuple (آرایهای با طول و تایپ مشخص)
type Point = [number, number];
interface غیرممکنه.۳. نحوه ارثبری و گسترش کد (Extending)
هر دو ابزار روش خاص خودشون رو برای گسترش دادن تایپها دارن.
interface از کلمه کلیدی extends استفاده میکنه که از نظر فکری به شیءگرایی (OOP) نزدیکتره، در حالی که type از عملگر & (Intersection) استفاده میکنه:// گسترش با Interface
interface Animal { name: string; }
interface Bear extends Animal { honey: boolean; }
// گسترش با Type
type AnimalType = { name: string; };
type BearType = AnimalType & { honey: boolean; };
امروز تو دنیای توسعه وب، توافقهای نانوشته اما استانداردی شکل گرفته که بر اساس اونها میشه از فرمول زیر برای پروژهها به استفاده کرد:
از Type استفاده کنید اگر:
•در حال طراحی کامپوننتهای فرانتاند (مثل Props در ریاکت و نکست) هستید؛ چون تایپها برای این کار تمیزترن، جلوی ادغامهای ناخواسته رو میگیرن و کار با قابلیتهای کامپوننت رو راحتتر میکنن.
•نیاز به تعریف Union Types دارید (مثلاً وضعیتهای یک دکمه یا کامپوننت:
'primary' | 'secondary' | 'danger').•میخواید رفتارهای پیچیدهای مثل کدهای داینامیک، تایپهای شرطی (Conditional Types) یا الیاسهای ساده برای کدهای پایه (Primitives) بسازید.
از Interface استفاده کنید اگر:
•ساختار دادههای دیتابیس، مدلها یا API (مثل خروجیهای Prisma یا آبجکتهای سمت بکآند) رو تعریف میکنید که فرمت کاملاً شیءگرا دارن.
•در حال نوشتن یک کتابخانه (Library) یا بسته نرمافزاری هستید و میخواید دیگران بتونن با قابلیت Declaration Merging، ویژگیهای جدیدی به متغیرهای شما اضافه کنن و اون رو گسترش بدن.