Дженерики — одна из самых мощных и одновременно пугающих возможностей TypeScript.

Базовый синтаксис

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

const num = identity(42);       // T = number
const str = identity("hello");  // T = string

Constraints (ограничения)

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

getLength("hello");  // OK: строки имеют length
getLength([1, 2, 3]); // OK: массивы имеют length
getLength(42);       // Error: у числа нет length

Conditional Types

type IsArray<T> = T extends any[] ? true : false;

type Check1 = IsArray<string[]>; // true
type Check2 = IsArray<string>;   // false

Infer

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type Fn = () => string;
type Result = ReturnType<Fn>; // string

Дженерики — это не магия, а математика типов. Начните с простых случаев и постепенно усложняйте.