Generics في TypeScript: دليل شامل حول الأدوية الجنسية

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

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

ابدأ الدورة
```html

مقدمة إلى Generics في TypeScript



TypeScript هي لغة مكتوبة بشكل صارم (Strictly Typed) تعمل على توسيع إمكانيات JavaScript بإضافة الكتابة الثابتة (Static Typing). ومع ذلك، فإن واحدة من أقوى وأكثر ميزاتها مرونة هي آلية Generics (الجينيريك). إذا سبق لك أن كتبت كودًا يجب أن يعمل مع أنواع مختلفة من البيانات، مع الحفاظ في نفس الوقت على أمان الأنواع (Type Safety)، فإن Generics هو بالضبط ما تحتاجه.



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



ما هي Generics ولماذا نحتاجها؟



Generics هي آلية تسمح بإنشاء مكونات (دوال، كلاسات، واجهات) قادرة على العمل مع أنواع مختلفة من البيانات، دون فقدان معلومات الأنواع. بدلاً من تثبيت نوع معين، تستخدم معامل نوع (Type Parameter) يتم استبداله عند الاستدعاء.



المشكلة بدون Generics



لنفترض أنك تريد كتابة دالة تقوم بإرجاع العنصر الأول من مصفوفة. بدون Generics، قد يبدو الأمر كالتالي:



function getFirstElement(arr: any[]): any {  return arr[0];}

const num = getFirstElement([1, 2, 3]); // النوع 'any' — لقد فقدنا المعلوماتconsole.log(num.toUpperCase()); // خطأ أثناء التنفيذ، لكن TypeScript لا يتحرك


هنا نستخدم any، ولا يستطيع TypeScript تحذيرنا من أن num هو رقم وليس سلسلة نصية. هذا يؤدي إلى أخطاء محتملة أثناء التنفيذ.



الحل مع Generics



الآن دعنا نعيد كتابة نفس الدالة باستخدام Generics:



function getFirstElement<T>(arr: T[]): T {  return arr[0];}

const num = getFirstElement([1, 2, 3]); // النوع 'number'const str = getFirstElement(['a', 'b', 'c']); // النوع 'string'

// num.toUpperCase(); // خطأ في الترجمة — TypeScript يعرف أن num هو رقم


الرمز <T> هو معامل النوع. يعمل كعنصر نائب (Placeholder): عندما نستدعي الدالة بمصفوفة أرقام، يصبح T هو number، وتحصل القيمة المُرجعة أيضًا على النوع number. بهذه الطريقة، نحافظ على الكتابة الصارمة دون فقدان المرونة.



كيفية استخدام Generics: السيناريوهات الأساسية



لا يتم تطبيق Generics في الدوال فقط، بل أيضًا في الكلاسات والواجهات والأنواع. دعنا نستعرض السيناريوهات الأكثر شيوعًا.



Generics في الدوال



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



function createPair<K, V>(key: K, value: V): { key: K; value: V } {  return { key, value };}

const pair = createPair('id', 123); // { key: string; value: number }console.log(pair.key.toUpperCase()); // يعمل// pair.key.toFixed(); // خطأ — key هو سلسلة نصية


هنا نستخدم معاملين للنوع: K للمفتاح و V للقيمة. يقوم TypeScript تلقائيًا باستنتاج الأنواع بناءً على الوسائط.



Generics في الكلاسات



تعتبر Generics مثالية لإنشاء كلاسات عامة، مثل الأكوام (Stacks) والطوابير (Queues) أو مخازن البيانات:



class Stack<T> {  private items: T[] = [];

push(item: T): void { this.items.push(item); }

pop(): T | undefined { return this.items.pop(); }

peek(): T | undefined { return this.items[this.items.length - 1]; }}

const numberStack = new Stack<number>();numberStack.push(10);numberStack.push(20);console.log(numberStack ```

المدونات

توصيات الكتب