آموزش

تفاوت interface و type در TypeScript؛ کِی از کدام استفاده کنیم؟

هر دو شکل یک آبجکت را توصیف می‌کنند، ولی یکی از این دو اجازه می‌دهد بعداً همان اسم را دوباره تعریف کنید — و همین برای کتابخانه‌ها فرق بزرگی می‌سازد.

تحریریه‌ی دینا کد
نویسنده
۳ دقیقه مطالعه۱ بازدید
اشتراک گذاری۱

جواب کوتاه: برای شکل یک آبجکت یا کلاس، interface بگیرید — چون باز است و کتابخانه‌ها می‌توانند بعداً بهش اضافه کنند. برای هرچیزی غیر از یک آبجکت ساده — یونیون، تقاطع، تاپل، یا یک تایپ مبتنی بر یک تایپ دیگر — فقط type این کار را بلد است.

interface را می‌شود دوباره تعریف کرد، type را نه

tsinterface User { name: string; }
interface User { age: number; }
const u: User = { name: 'سارا', age: 20 }; // درست کامپایل می‌شود
tstype User = { name: string };
type User = { age: number };
// error TS2300: Duplicate identifier 'User'.

این ویژگی — declaration merging — دلیل اصلی است که تایپ‌های کتابخانه‌ها (مثل express یا خودِ DOM در lib.dom.d.ts) با interface نوشته می‌شوند: هر پکیج می‌تواند یک تعریف را گسترش بدهد، بدون اینکه تعریف اصلی را عوض کند.

type کاری بلد است که interface نه: یونیون

tstype Status = 'draft' | 'published' | 'archived';
let s: Status = 'draft';
s = 'weird';
// error TS2322: Type '"weird"' is not assignable to type 'Status'.

هیچ interfaceـی نمی‌تواند یک یونیون از رشته‌های ثابت را نشان بدهد — یونیون فقط با type تعریف می‌شود.

extends در interface، & در type

tsinterface Animal { name: string }
interface Dog extends Animal { breed: string }
tstype Animal = { name: string };
type Dog = Animal & { breed: string };

هر دو همان چیز را می‌سازند — یک Dog که هم name دارد هم breed — فقط با نحو متفاوت. برای این حالت ساده، فرقی در نتیجه نمی‌کند؛ فرق وقتی است که به declaration merging یا یونیون نیاز دارید.

قانون عملی

نیاز انتخاب
شکل یک آبجکت/کلاس که ممکن است بعداً گسترش پیدا کند interface
یونیون، تقاطع، تاپل، یا هر چیزی غیر از آبجکت ساده type
تایپ کتابخانه‌ای که دیگران باید بتوانند augment کنند interface

کاری که فقط type بلد است: نگاشت روی کلیدها

tstype Flags = { a: boolean; b: boolean };
type OptionalFlags = { [K in keyof Flags]?: Flags[K] };

این «mapped type» با موفقیت کامپایل می‌شود، ولی همین نحو روی interface اصلاً syntax معتبر نیست — کامپایلر همان‌جا با «] expected» متوقف می‌شود. اینجا هم همان قانون است: هر چیزی که از روی یک تایپ دیگر ساخته می‌شود (union، mapped، conditional)، فقط با type قابل نوشتن است؛ interface فقط یک شکل ثابت را توصیف می‌کند.

اگر تیم‌تان یکی از این دو را به‌عنوان استاندارد انتخاب کرده، همان را دنبال کنید — ثباتِ سبک مهم‌تر از برتری فنی جزئی است. اگر تازه با TypeScript شروع کرده‌اید، دوره‌ی TypeScript این تصمیم‌ها را با پروژه‌ی واقعی جا می‌اندازد.

تحریریه‌ی دینا کد
نویسنده

نظرها

اولین نفری باشید که نظر می‌دهد
برای ثبت نظر وارد شوید

سؤالتان را بپرسید یا تجربه‌تان را بنویسید — نویسنده‌ی مطلب پاسخ می‌دهد.

مطالب مرتبط

از همین دسته
آموزش

چرا Rust به‌جای segfault، خطای کامپایل می‌دهد

در C یا ++C یک اشاره‌گر نامعتبر معمولاً ماه‌ها بعد، در پروداکشن، خودش را نشان می‌دهد. در Rust همان اشتباه، همان لحظه‌ی کامپایل متوقفت می‌کند.

تحریریه‌ی دینا کد۵ دقیقه
تفاوت interface و type در TypeScript — دینا کد