Generics في TypeScript: لماذا هي ضرورية وكيفية استخدامها عمليًا

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: ما هي Generics ولماذا هي مهمة

TypeScript هي لغة مكتوبة بشكل صارم، تضيف نظام أنواع قوي إلى JavaScript. ومع ذلك، فإن التصنيف الصارم يعيق أحيانًا كتابة كود مرن وقابل لإعادة الاستخدام. وهنا تأتي Generics (الأدوية الجنيسة، الأنواع العامة) للإنقاذ.

Generics هي أداة تسمح بإنشاء مكونات (دوال، كلاسات، واجهات) تعمل مع أنواع بيانات مختلفة، دون فقدان التحكم في الأنواع. تخيل أنك تكتب دالة يجب أن تعمل مع الأرقام والسلاسل النصية والمصفوفات. بدون الأدوية الجنيسة، سيكون عليك إما استخدام any (مما يقتل فائدة التصنيف) أو إنشاء دوال منفصلة لكل نوع بيانات. تحل Generics هذه المشكلة بأناقة وأمان.

في هذه المقالة، سنشرح لماذا نحتاج إلى الأدوية الجنيسة في TypeScript، والأهم من ذلك، كيفية استخدامها عمليًا - من الدوال البسيطة إلى الكلاسات المعقدة وقيود الأنواع.



الجزء الرئيسي



1. Generics في الدوال: من النظرية إلى التطبيق

أبسط وأكثر مثال شائع لاستخدام الأدوية الجنيسة هو الدوال التي تستقبل وترجع بيانات من نفس النوع. لننظر إلى مشكلة كلاسيكية: دالة تُرجع العنصر الأول من مصفوفة.



النهج السيء (بدون Generics):

// مثال مع any - نفقد معلومات النوعfunction getFirst(arr: any[]): any {    return arr[0];}

const num = getFirst([1, 2, 3]); // نوع num هو any، لا نعرف أنه رقم


النهج الصحيح (مع Generics):

// استخدام النوع العام Tfunction getFirst<T>(arr: T[]): T {    return arr[0];}

const num = getFirst([1, 2, 3]); // نوع num هو numberconst str = getFirst(['a', 'b', 'c']); // نوع str هو stringconst bool = getFirst([true, false]); // نوع bool هو boolean


كيف يعمل هذا؟ نعلن عن معامل نوع <T> (يمكن أن يكون الاسم أي شيء، ولكن حسب الاتفاقية تُستخدم T و U و V). يقوم TypeScript تلقائيًا باستنتاج النوع المحدد بناءً على الوسيطة المُمررة. يُسمى هذا استنتاج الأنواع.



يمكنك أيضًا تحديد النوع صراحةً عند استدعاء الدالة:

const num = getFirst<number>([1, 2, 3]); // تحديد النوع صراحة


مثال مفيد آخر - دالة تُرجع عنصرًا عشوائيًا من مصفوفة:

function getRandom<T>(items: T[]): T {    const randomIndex = Math.floor(Math.random() * items.length);    return items[randomIndex];}

const randomNumber = getRandom([10, 20, 30]); // النوع — numberconst randomName = getRandom(['آنا', 'إيفان', 'ماريا']); // النوع — string


2. Generics في الواجهات والأنواع

تعمل الأدوية الجنيسة بشكل ممتاز أيضًا مع الواجهات. وهذا يسمح بإنشاء هياكل بيانات مرنة يمكنها تخزين قيم من أنواع مختلفة.



تخيل أننا نريد وصف استجابة API، والتي قد تحتوي على بيانات من أي نوع:

interface ApiResponse<T> {    status: number;    message: string;    data: T;}

// الاستخدام لأنواع بيانات مختلفةconst userResponse: ApiResponse<{ id: number; name: string }> = { status: 200, message: 'تم بنجاح', data: { id: 1, name: 'أليكسي' }};

const listResponse: ApiResponse<string[]> = { status: 200, message: 'تم الحصول على القائمة', data: ['تفاح', 'موز', 'برتقال']};


يمكن أيضًا استخدام الأدوية الجنيسة مع الأسماء المستعارة للأنواع (type):

type Result<T> = {    success: boolean;    value: T;    error?: string;};

const successResult: Result<number> = { success: true, value: 42 };const errorResult: Result<string> = { success: false, error: 'خطأ في التحميل', value: '' };


لاحظ: يمكننا أن

المدونات

توصيات الكتب