جنریک‌ها تا روزی که از نوشتن سه تابع تکراری نجاتت ندهند، به نظر آکادمیک می‌آیند. بگذارید از پایه شهریت بسازیم.

لحظه‌ی هویتی

typescript
function identity<T>(value: T): T {
  return value;
}

identity<string>("hello"); // string
identity(42);              // number — استنتاج خودکار

T یک نوع جایگزین است: فراخوان‌ها تصمیم می‌گیرند چه باشد.

تابعی که واقعاً استفاده می‌کنی

typescript
function firstElement<T>(arr: T[]): T | undefined {
  return arr[0];
}

const name = firstElement(["آنا", "بن"]); // string | undefined

محدودیت‌ها

typescript
function getLength<T extends { length: number }>(item: T): number {
  return item.length;
}

getLength("text");   // 4
getLength([1, 2]);   // 2

تایپ شرطی — حرکت قدرتمند

typescript
type Unwrap<T> = T extends Promise<infer U> ? U : T;

type A = Unwrap<Promise<number>>; // number
type B = Unwrap<string>;          // string

کامپوننت جنریک

tsx
function Stack<T extends { id: string }>({ items }: { items: T[] }) {
  return <div>{items.map((i) => <span key={i.id}>{i.id}</span>)}</div>;
}

قوانین طلایی

  1. به استنتاج اعتماد کن؛ فقط وقتی حاشیه‌نویسی کن که استنتاج شکست بخورد.
  2. با extends محدود کن، نه any.
  3. برای حالت‌های ساده T، وگرنه اسم واقعی بده (TItem).

جنریک‌ها فقط نوع‌هایی با پارامتر هستند. وقتی این را با صدای بلند بگویی، سردرد حل می‌شود.