ما هي Generics في JavaScript ولماذا تحتاجها؟
\n\nتخيل أنك تكتب دالة يجب أن تعمل مع أنواع مختلفة من البيانات - الأرقام، النصوص، الكائنات. بدون Generics (الجينيريكس)، سيكون عليك إما تكرار الكود أو استخدام any، مما يفقدك السيطرة على الأنواع. Generics هي آلية تسمح لك بإنشاء مكونات (دوال، كلاسات، واجهات) تعمل مع أي نوع بيانات، ولكن مع الحفاظ على معلومات النوع.
على الرغم من أن JavaScript هي لغة ذات كتابة ديناميكية، إلا أن نظام Node.js يستخدم بنشاط TypeScript، الذي يضيف الكتابة الثابتة. في TypeScript، تتجلى قوة الجينيريكس بشكل كامل. ومع ذلك، فإن فهم مبادئها مفيد حتى لـ JavaScript النقي - خاصة إذا كنت تكتب مكتبات أو تعمل مع أطر العمل الحديثة.
\n\nفي هذه المقالة، سنشرح:
\n- \n
- لماذا تحتاج Generics \n
- كيفية تعريف واستخدام الجينيريكس في TypeScript \n
- أمثلة لـ Node.js (API، معالجة البيانات) \n
- القيود وأفضل الممارسات \n
أساسيات Generics: الصيغة والأمثلة الأساسية
\n\nأول جينيريك: دالة الهوية
\n\nالمثال الكلاسيكي - دالة تعيد ما تستقبله:
\n\n// بدون Generics\nfunction identity(value: any): any {\n return value;\n}\n\n// مع Generics\nfunction identity<T>(value: T): T {\n return value;\n}\n\n// الاستخدام\nconst num = identity<number>(42); // num هو number\nconst str = identity<string>('مرحباً'); // str هو string\n\n\nالرمز <T> هو معامل النوع. يمكنك تسميته كما تشاء (T، U، Item)، لكن التقاليد تتطلب استخدام T (من Type).
جينيريكس مع عدة معاملات
\n\nأحياناً تحتاج للعمل مع عدة أنواع في وقت واحد:
\n\nfunction pair<T, U>(first: T, second: U): [T, U] {\n return [first, second];\n}\n\nconst result = pair<number, string>(1, 'واحد');\n// result: [number, string]\n\n\nجينيريكس في الدوال السهمية (Node.js)
\n\nفي React أو الأدوات المساعدة، غالباً ما تستخدم الدوال السهمية مع الجينيريكس:
\n\nconst wrapInArray = <T>(item: T): T[] => {\n return [item];\n};\n\nconst arr = wrapInArray('اختبار'); // arr: string[]\n\n\nتطبيق Generics في مشاريع Node.js الحقيقية
\n\nمعالجات API مع استجابات محددة الأنواع
\n\nتخيل أنك تكتب دالة عامة للاستعلامات إلى API. بدون الجينيريكس، ستفقد أنواع البيانات:
\n\n// سيء: any\nasync function fetchData(url: string): Promise<any> {\n const response = await fetch(url);\n return response.json();\n}\n\n// جيد: Generics\nasync function fetchData<T>(url: string): Promise<T> {\n const response = await fetch(url);\n return response.json();\n}\n\n// الاستخدام\ninterface User {\n id: number;\n name: string;\n}\n\nconst user = await fetchData<User>('/api/user/1');\nconsole.log(user.name); // TypeScript يعلم أن name هو string\n\n\nمجموعات بيانات محددة الأنواع
\n\nعند العمل مع قواعد البيانات (مثل Prisma أو Mongoose)، تساعد الجينيريكس في إنشاء مستودعات عامة:
\n\nclass Repository<T extends { id: number }> {\n private items: T[] = [];\n\n add(item: T): void {\n this.items.push(item);\n }\n\n getById(id: number): T | undefined {\n return this.items.find(item => item.id === id);\n }\n}\n\n// الاستخدام\ninterface Product {\n id: number;\n title: string;\n price: number;\n}\n\nconst productRepo = new Repository<Product>();\nproductRepo.add({ id: 1, title: 'لابتوب', price: 1000 });\nconst laptop = productRepo.getById(1);\n\n\nأغلفة لمعالجة الأخطاء
\n\nدالة عامة لـ