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

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

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

ابدأ الدورة

مقدمة: لماذا يحتاج JavaScript إلى Generics؟



غالبًا ما يواجه التطوير باستخدام JavaScript (خاصة في بيئة Node.js) مشكلة تكرار الكود. تخيل أنك بحاجة إلى كتابة دالة تعمل مع الأرقام والسلاسل النصية والمصفوفات. بدون Generics (الأدوية العامة)، ستكتب إما عدة تحميلات زائدة أو ستستخدم any، مما يفقدك كل سحر الأنواع.



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



في هذه المقالة، سنستعرض لماذا نحتاج إلى الأدوية العامة، وكيفية استخدامها عمليًا في Node.js، ولماذا تجعل كودك أكثر أمانًا وقابلية لإعادة الاستخدام.



1. Generics في TypeScript: أساس أمان الأنواع



على الرغم من أن JavaScript النقي لا يحتوي على دعم مدمج للأدوية العامة، إلا أن TypeScript (الطبقة الفوقية لـ JS) يوفرها بشكل كامل. لهذا السبب، تستخدم جميع الأطر والمكتبات الحديثة لـ Node.js (مثل NestJS و Express مع الأنواع) هذه الأدوية العامة بنشاط.



مثال بسيط: دالة الهوية (identity)



المثال الكلاسيكي هو دالة تعيد ما تستقبله:



// بدون generics — نستخدم any (نفقد النوع)function identity(arg: any): any {  return arg;}

// مع generic — يتم الحفاظ على النوعfunction identity<T>(arg: T): T { return arg;}

// الاستخدامconst num = identity<number>(42); // النوع: numberconst str = identity<string>('hello'); // النوع: string


لاحظ: <T> هو معامل النوع. نقول لـ TypeScript: "سيتم تمرير النوع لاحقًا". يقوم المترجم تلقائيًا باستنتاج النوع، لذا يمكنك غالبًا كتابة identity(42) فقط.



لماذا هذا مهم لـ Node.js؟



في Node.js، تعمل باستمرار مع واجهات برمجة التطبيقات (APIs) وقواعد البيانات والخدمات الخارجية. تسمح لك الأدوية العامة بضمان أن البيانات تأتي بالتنسيق الذي تتوقعه بالضبط:



// دالة للعمل مع APIasync function fetchData<T>(url: string): Promise<T> {  const response = await fetch(url);  return response.json() as Promise<T>;}

// الآن نعرف البنية الدقيقة للاستجابةinterface User { id: number; name: string;}

const user = await fetchData<User>('/api/user/1');// user.name — سلسلة نصية، user.id — رقم (يتحقق TypeScript من ذلك)


2. سيناريوهات عملية: العمل مع المصفوفات والمجموعات



تكون الأدوية العامة مفيدة بشكل خاص عند العمل مع المصفوفات ومجموعات البيانات. دعنا نلقي نظرة على مثال حقيقي من Node.js — دالة التصفية والتحويل.



دالة عامة للتحويل (mapping)



// دالة تحول مصفوفة من نوع إلى مصفوفة من نوع آخرfunction mapArray<T, U>(items: T[], mapper: (item: T) => U): U[] {  return items.map(mapper);}

// مثال: نحصل على الأسماء فقط من Userinterface User { id: number; name: string; email: string;}

const users: User[] = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' }];

const names: string[] = mapArray(users, (user) => user.name);// names: ['Alice', 'Bob'] — النوع string[] مضمون


هنا <T, U> هما معاملان للنوع. T هو نوع المصفوفة المدخلة، U هو نوع النتيجة. هذا يوفر أقصى مرونة دون فقدان الأنواع.



كلاس عام للمكدس (Stack)



في Node.js، غالبًا ما تكون هناك حاجة إلى هياكل بيانات. لننشئ مكدسًا آمنًا من حيث الأنواع:



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

pu

المدونات

توصيات الكتب