لو عندك دالة بتاخد array وترجّع أول عنصر فيه، وعامل منها نسخة لـ string[] وتانية لـ number[] وتالتة لـ User[]، أنت بتعيد نفس اللوجيك 3 مرات. Generics في TypeScript بتخليك تكتبها مرة واحدة مع الحفاظ على الـ type بالظبط لكل نداء.
TypeScript Generics من غير لف
المشكلة باختصار
فيه طريقتين شائعتين للتعامل مع دوال بتشتغل على أكتر من نوع، وكلاهما بيجيب مشاكل في production:
- تكرار الدالة لكل نوع: كود ميت وصيانة مكلّفة.
- استخدام
any: بتفقد كل فوائد TypeScript وبترجع لحالة JavaScript النقية.
Generic param هو ببساطة نوع متغيّر بيتحدّد وقت النداء. نفس الفكرة زي بارامتر عادي في دالة، بس بتمرّر فيه نوع بدل قيمة.
أول مثال: دالة identity
الصيغة الأساسية: حرف واحد (العُرف T) بين <> بعد اسم الدالة.
function identity<T>(value: T): T {
return value;
}
const a = identity(42); // a: number
const b = identity("hello"); // b: string
const c = identity([1, 2, 3]); // c: number[]
ركّز على حاجة مهمة: TypeScript استنتج T تلقائيًا من الـ argument. مش لازم تكتب identity<number>(42) إلا لو الاستنتاج فشل أو مش واضح.
مثال أقرب للشغل اليومي: getFirst
function getFirst<T>(items: T[]): T | undefined {
return items[0];
}
interface User { id: string; name: string; }
const users: User[] = [{ id: "1", name: "Ahmed" }];
const first = getFirst(users); // first: User | undefined
console.log(first?.name); // TypeScript عارف إن فيه name
قارنها بالإصدار بـ any:
function getFirstBad(items: any[]): any {
return items[0];
}
const first = getFirstBad(users);
first.nammmme; // لا خطأ compile، bug في runtime