لماذا Generics؟
تخيّل دالة تُرجع ما تستقبله. بـ any تفقد النوع:
function identity(value: any): any {
return value;
}
let x = identity("نص"); // النوع any — ضاعت الحماية
بـ Generics نحافظ على النوع:
function identity<T>(value: T): T {
return value;
}
let a = identity<string>("نص"); // string
let b = identity(42); // number (مستنتَج)
T متغيّر نوع — يُملأ بالنوع الفعلي عند الاستدعاء.
دالة عامّة على مصفوفة
function firstItem<T>(arr: T[]): T {
return arr[0];
}
const first = firstItem([10, 20, 30]); // number
const name = firstItem(["علي", "سارة"]); // string
القيود (Constraints)
نقيّد النوع العام بـ extends ليملك خصائص معيّنة:
function logLength<T extends { length: number }>(item: T): T {
console.log(item.length);
return item;
}
logLength("نص"); // للنصوص length
logLength([1, 2, 3]); // للمصفوفات length
logLength(42); // خطأ! الرقم بلا length
أصناف عامّة
class Box<T> {
private content: T;
constructor(value: T) {
this.content = value;
}
get(): T {
return this.content;
}
}
const numberBox = new Box<number>(100);
console.log(numberBox.get()); // 100
مثال واقعي: استجابة API
interface ApiResponse<T> {
status: number;
data: T;
}
const userRes: ApiResponse<{ name: string }> = {
status: 200,
data: { name: "نور" },
};
أخطاء شائعة
- استخدام
anyبدل Generics فتضيع علاقة الأنواع بين المدخل والمخرج. - تسمية متغيّر النوع
Tفقط دائمًا — استخدم أسماء معبّرة مثلTItem.
🎯 التالي: الأنواع المساعدة (Utility Types) وkeyof.