لماذا التصنيف هو قوة خارقة وليس عبئًا
\n\nتخيل: أنت تكتب كودًا، كل شيء يعمل، أنت سعيد. ثم فجأة! — خطأ أحمر في وحدة التحكم: Cannot read property 'name' of undefined. مألوف؟ مرحبًا بك في عالم JavaScript بدون أنواع. لكن هناك خبر جيد: JavaScript الحديثة (وخاصة TypeScript) تقدم أداة قوية — Generics (الأنواع العامة). هذه ليست مجرد "ميزة أخرى"، بل طريقة حقيقية لجعل الكود أنظف وأكثر أمانًا وأوضح.
في هذه المقالة، سنشرح ما هو التصنيف في JavaScript، وكيف تعمل الأنواع العامة (generics) ولماذا يجب استخدامها في كل مشروع. لا نظرية جافة — فقط أمثلة حية ونصائح عملية.
\n\nما هي الأنواع العامة (Generics) ولماذا نحتاجها؟
\n\nGenerics (الأنواع العامة) هي آلية تسمح بكتابة دوال وفئات وواجهات تعمل مع أنواع بيانات مختلفة، مع الحفاظ على تصنيف صارم. ببساطة: تقوم بإنشاء كود "عالمي" يتكيف تلقائيًا مع نوع البيانات الذي يعمل معه.
\n\nبدون الأنواع العامة، كنت ستكتب شيئًا مثل:
\n\nfunction identity(arg: any): any {\n return arg;\n}\n\nالمشكلة؟ any يقتل كل التصنيف. تفقد معلومات النوع، ولن يتمكن المترجم من تحذيرك من الخطأ. مع Generics الأمر مختلف تمامًا:
function identity<T>(arg: T): T {\n return arg;\n}\n\n// الاستخدام\nlet num = identity<number>(42); // النوع number\nlet str = identity<string>("مرحبًا"); // النوع string\n\nسحر؟ لا، مجرد تصنيف ذكي. النوع T هو عنصر نائب يتم استبداله بالنوع الفعلي عند استدعاء الدالة.
Generics ضد any: معركة من أجل الأمان
\n\nيسأل الكثير من المبتدئين: "لماذا نتعب أنفسنا مع الأنواع العامة، إذا كان بإمكاننا استخدام any؟" الإجابة بسيطة: أمان الأنواع ليس من أجل "أن يكون جميلًا"، بل لمنع الأخطاء في وقت التشغيل.
انظر إلى هذا المثال بدون Generics:
\n\nfunction getLength(data: any): number {\n return data.length; // إذا كانت data رقمًا، سيكون هناك خطأ\n}\n\ngetLength(42); // undefined في وقت التشغيل\n\n\nمع الأنواع العامة، تحدد بوضوح أن الدالة تعمل مع المصفوفات أو السلاسل النصية:
\n\nfunction getLength<T extends { length: number }>(data: T): number {\n return data.length;\n}\n\ngetLength([1,2,3]); // 3\ngetLength("hello"); // 5\n// getLength(42); // خطأ في الترجمة — الرقم لا يحتوي على length\n\n\nهل ترى الفرق؟ يتم اكتشاف الخطأ في مرحلة كتابة الكود، وليس في بيئة الإنتاج. هذا هو جوهر التصنيف المتقدم.
\n\nأمثلة عملية على Generics في JavaScript
\n\nدعنا نستعرض بعض السيناريوهات الواقعية حيث تنقذ الأنواع العامة الموقف حقًا.
\n\n1. دوال عامة (Generic functions) للعمل مع المصفوفات
\n\nلنفترض أنك تكتب أداة لاستخراج العنصر الأول من مصفوفة:
\n\nfunction first<T>(arr: T[]): T | undefined {\n return arr[0];\n}\n\nconst numbers = [10, 20, 30];\nconst firstNum = first(numbers); // النوع number | undefined\n\nconst strings = ["a", "b", "c"];\nconst firstStr = first(strings); // النوع string | undefined\n\n\nبدون الأنواع العامة، كان عليك كتابة دالتين منفصلتين أو استخدام any. مع تصنيف JavaScript عبر Generics — دالة واحدة تعمل مع جميع الأنواع.
2. فئات عامة (Generic classes) لتخزين البيانات
\n\nتخيل أنك تنشئ غلافًا بسيطًا لتخزين قيمة:
\n\nclass Box<T> {\n private content: T;\n\n constructor(initial: T) {\n this.content = initial;\n }\n\n getValue(): T {\n return this.content;\n }\n\n setValue(value: T): void {\n this.content = value;\n }\n}\n\n// الاستخدام\nconst numberBox