Generics: введение
Generics позволяют писать функции и типы, работающие с разными типами, сохраняя типовую безопасность.
Проблема
Без дженериков функция принимает any и теряет тип:
function identity(value: any): any {
return value;
}
const result = identity('hello');
result.toFixed(2); // нет ошибки, но упадёт в рантайме
Дженерик-функция
function identity<T>(value: T): T {
return value;
}
const a = identity('hello'); // string
const b = identity(42); // number
<T> — параметр типа. TypeScript выводит его из аргумента.
Явное указание
identity<string>('hello');
identity<number>(42);
Обычно не нужно — тип выводится.
Несколько параметров
function pair<A, B>(a: A, b: B): [A, B] {
return [a, b];
}
pair('x', 1); // [string, number]
Дженерик-массивы
function first<T>(items: T[]): T | undefined {
return items[0];
}
first([1, 2, 3]); // number | undefined
first(['a', 'b']); // string | undefined
Дженерик-интерфейсы
interface Box<T> {
value: T;
}
const box: Box<string> = { value: 'hello' };
Дженерик-типы
type Result<T> = {
data: T;
error: string | null;
};
type UserResult = Result<User>;
type PostResult = Result<Post>;
Соответствие типов
TypeScript проверяет, что тип совпадает:
function identity<T>(value: T): T {
return value;
}
const n: number = identity('hello'); // ошибка
С ограничением
function logLength<T extends { length: number }>(value: T): T {
console.log(value.length);
return value;
}
logLength('hello'); // ок
logLength([1, 2, 3]); // ок
logLength(42); // ошибка
extends ограничивает возможные типы.
Значение по умолчанию
type Box<T = string> = {
value: T;
};
const box: Box = { value: 'hello' }; // T = string
Классы
class Stack<T> {
private items: T[] = [];
push(item: T) {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
const stack = new Stack<number>();
stack.push(1);
stack.push('a'); // ошибка
Async
async function fetchData<T>(url: string): Promise<T> {
const res = await fetch(url);
return res.json();
}
const user = await fetchData<User>('/api/user');
Итоги
- Дженерики — параметры типа
- Синтаксис
<T> - TypeScript выводит тип из аргумента
extends— ограничение- Работают с функциями, типами, классами
- Сохраняют типовую безопасность