Загрузка…
Загрузка…
TypeScript · middle · сложность 5
Generics — параметры на уровне типов: функция или тип сохраняет связь между входами и выходами вместо схлопывания в any. Мастерство — поставить type parameter туда, где inference захватит его из аргументов, а не заставлять callers писать его руками.
Generic — «функция от типов». identity<T>(x: T): T помнит, что вернул то же, что принял. Без T пришлось бы any или дублировать.
Ставьте T на аргументах, не только на return: иначе inference не из чего взять. Constraints (extends) добавляют возможности. Несколько параметров (T, K extends keyof T) моделируют безопасный доступ к полям.
В React/API слое generics протаскивают тип ответа через Promise<T>, хуки и компоненты списков.
// Generic preserves the input→output relationship; inference fills T
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const n = first([1, 2, 3]); // T = number → number | undefined
const s = first(['a', 'b']); // T = string → string | undefined
// ❌ any loses the type; caller gets no help downstream
function firstBad(arr: any[]): any { return arr[0]; }
const x = firstBad([1, 2]); // x: any — unsafe from here on
// Multiple type params chain through composition
function map<T, U>(arr: T[], fn: (x: T) => U): U[] {
return arr.map(fn);
}
map([1, 2], n => `#${n}`); // T=number inferred, U=string inferred → string[]
// ❌ Unusable generic — T appears only in return; nothing to infer from
function create<T>(): T { return {} as T; } // caller MUST annotate; smell// Generic container: remembers what it holds
class Stack<T> {
private items: T[] = [];
push(x: T) { this.items.push(x); }
pop(): T | undefined { return this.items.pop(); }
}
const s2 = new Stack<string>(); // or inferred from first push in some casesGenerics сохраняют identity типа через пайплайн; пишите так, чтобы inference работал сам, а any не подменял параметр типа.