مقدمة: لماذا TypeScript أمر لا غنى عنه للمطور الحديث
\nرسّخ TypeScript مكانته كمعيار واقعي في تطوير المؤسسات. وفقًا لاستطلاعات Stack Overflow، أكثر من 70% من مطوري الواجهات الأمامية يستخدمون أو يخططون لاستخدام TypeScript. في المقابلات، لا تخلو الأسئلة حول هذه التقنية - حتى لو كان المنصب مذكورًا رسميًا باسم "مطور JavaScript".
\nفي هذه المقالة، سنستعرض المواضيع الرئيسية التي سيسألك عنها بالتأكيد في المقابلة الفنية: من الأنواع الأساسية إلى الأدوية المعقدة والأنواع الشرطية. تم بناء المحتوى على مبدأ "من البسيط إلى المعقد" لتتمكن من التحضير بشكل منهجي.
\n\n1. الأساسيات: الأنواع والواجهات والاختلافات بينهما
\n1.1. الأنواع البدائية والخاصة
\nلنبدأ بالأساسيات. من شبه المؤكد أن المحاور سيسأل عن any وunknown وnever وvoid.
- \n
any- يعطل التحقق من الأنواع. يُستخدم فقط كحل أخير أثناء الترحيل. \n unknown- بديل آمن لـ any. يتطلب التحقق من النوع قبل الاستخدام. \n never- النوع الذي لا يحدث أبدًا (الدوال التي ترمي استثناءات أو الحلقات اللانهائية). \n void- عدم وجود قيمة مرتجعة من الدالة. \n
function throwError(msg: string): never {\n throw new Error(msg);\n}\n\nfunction log(msg: string): void {\n console.log(msg);\n}\n\nlet data: unknown = JSON.parse('{"name":"John"}');\n// data.name // خطأ! تحتاج إلى تحقق\nif (typeof data === 'object' && data !== null) {\n console.log((data as Record<string, unknown>).name);\n}\n\n1.2. Interface مقابل Type: أيهما تختار؟
\nهذا سؤال كلاسيكي. كلا النهجين يسمحان بوصف بنية الكائن، لكن هناك فروق دقيقة:
\n- \n
- Interface - قابل للتوسيع (
extends)، ويمكن دمجه (declaration merging). \n - Type - يمكنه وصف أنواع الاتحاد (union-types)، والتقاطع (intersection)، والأنواع البدائية. لا يخضع لـ declaration merging. \n
// Interface - توسيع\ninterface User {\n name: string;\n}\ninterface User {\n age: number; // declaration merging\n}\nconst user: User = { name: 'Alice', age: 30 };\n\n// Type - اتحاد\ntype Status = 'active' | 'inactive';\ntype UserOrStatus = User | Status;\nنصيحة: بالنسبة للكائنات والكلاسات، استخدم interface، وبالنسبة للتركيبات المعقدة، استخدم type.
2. الأدوية (Generics) والأنواع المساعدة (Utility Types)
\n2.1. الأدوية: البرمجة العامة
\nلا تخلو أي مقابلة جادة من الأدوية. القدرة على كتابة نوع يتكيف مع الوسيط المُمرر هي مؤشر على نضج المطور.
\n// دواء بسيط\nfunction identity<T>(arg: T): T {\n return arg;\n}\n\n// تقييد الدواء\nfunction getLength<T extends { length: number }>(arg: T): number {\n return arg.length;\n}\n\n// دواء لمصفوفة\nfunction last<T>(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\nغالبًا ما يُسأل عن infer - الكلمة المفتاحية لاستنتاج الأنواع داخل الهياكل الشرطية:
\n// استخراج نوع العنصر من Promise\ntype Unwrap<T> = T extends Promise<infer U> ? U : T;\ntype Result = Unwrap<Promise<number>>; // number\n\n2.2. الأنواع المساعدة (Utility Types)
\nمعرفة الأدوات المساعدة المضمنة هي الحد الأدنى الإلزامي. قد يطلب المحاور تنفيذ بديل يدويًا.
\n- \n
Partial<T>- جميع الحقول تصبح اختيارية. \n Required<T>- جميع الحقول إلزامية. \n Pick<T, K>- يختار فقط المفاتيح المحددة. \n Omit<T, K>- يستبعد المفاتيح المحددة.