هل يمكن توسيع الأنواع في TypeScript؟ نتعمق في الأداء والتحسين
مرحبًا يا صديقي! إذا كنت قد كتبت يومًا بلغة TypeScript، فمن المؤكد أنك واجهت السؤال: "هل يمكن توسيع الأنواع بنفس طريقة توسيع الواجهات؟" هذا السؤال على Stack Overflow حصد آلاف المشاهدات، وليس من دون سبب. يبدو الأمر بسيطًا: يتم توسيع الواجهات باستخدام extends، بينما يتم توسيع الأنواع من خلال التقاطعات (&). لكن هناك تفاصيل دقيقة تؤثر بشكل مباشر على أداء الكود وسهولة قراءته.
اليوم سنتعمق في كيفية توسيع الأنواع في TypeScript، وما الفرق بين ذلك وبين الواجهات، وكيف لا نرتكب أخطاء عند التحسين. هيا بنا!
Type vs Interface: معركة أبدية
قبل الحديث عن التوسيع، دعنا نتذكر الفرق. الواجهات هي "عقود" يمكن الإعلان عنها عدة مرات (الدمج التصريحي)، بينما الأنواع هي أسماء مستعارة لأي شكل. يمكن توسيع كليهما، ولكن بطرق مختلفة.
كيفية توسيع الواجهات؟
الأمر مألوف تمامًا:
interface Animal { name: string;}
interface Bear extends Animal { honey: boolean;}
const bear: Bear = { name: 'Winnie', honey: true };بسيط، أنيق، ويعمل. ولكن ماذا لو أردنا نفس الشيء للنوع؟
كيفية توسيع الأنواع؟
الأنواع لا تدعم extends بشكل مباشر. بدلاً من ذلك، يتم استخدام عامل التقاطع (&):
type Animal = { name: string;};
type Bear = Animal & { honey: boolean };
const bear: Bear = { name: 'Winnie', honey: true };يبدو متشابهًا، لكن هناك مطبات. دعنا نستعرضها بالأمثلة.
الأداء: أيهما أسرع؟
سؤال المليون: هل يؤثر اختيار interface extends أو type & على سرعة الترجمة والتنفيذ؟ المفاجأة: نعم، ولكن ليس بالطريقة التي تظنها.
الترجمة: الواجهات تتفوق
يقوم TypeScript بترجمة الواجهات بشكل أسرع من تقاطعات الأنواع. لماذا؟ الواجهات هي هياكل "مسطحة" يمكن للمترجم تخزينها مؤقتًا ومعالجتها خطيًا. تقاطعات الأنواع هي تركيبات معقدة قد تتطلب توسيعًا متكررًا.
// واجهة - سريعةinterface A { a: string }interface B extends A { b: number }
// نوع - أبطأtype A = { a: string }type B = A & { b: number }في المشاريع الكبيرة التي تحتوي على مئات الأنواع، قد يكون الفرق ملحوظًا. ولكن إذا كان لديك 10-20 كيانًا، فلن تشعر به.
التنفيذ: لا فرق على الإطلاق
TypeScript هي طبقة فوق JavaScript. في وقت التشغيل، لا توجد واجهات ولا أنواع. فهي موجودة فقط في مرحلة التطوير. لذلك، لا يؤثر الاختيار على سرعة تنفيذ البرنامج على الإطلاق.
متى تكون الأنواع أفضل من الواجهات؟
على الرغم من بطء الترجمة المحتمل، فإن الأنواع لا غنى عنها في بعض السيناريوهات:
- Union types — دمج الأنواع (مثل
string | number) - Conditional types — الأنواع الشرطية (مثل
T extends string ? 'yes' : 'no') - Mapped types — تحويل الخصائص (مثل
{ [K in keyof T]: boolean })
الواجهات لا تستطيع التعامل مع هذا. ولكن إذا كنت تحتاج فقط إلى توسيع كائن — فالواجهات هي الأفضل.
التحسين: كيف لا تؤذي نفسك
الآن إلى الجزء الأكثر إثارة للاهتمام. كيف تكتب أنواعًا قابلة للتوسيع دون إبطاء الترجمة أو إرباك الزملاء؟
القاعدة 1: استخدم الواجهات للكائنات، والأنواع لكل شيء آخر
هذا هو المعيار الذهبي. إذا كنت تصف شكل كائن — استخدم interface. إذا كنت تحتاج إلى union أو intersection أو سحر مع الأدوية الجنسية — استخدم type.
// جيدinterface User { id: number; name: string;}
type Status = 'active' | 'inactive';type Admin = User & { role: 'admin' };