JavaScript & TypeScriptМодуль 8: Продвинутый TypeScript
Generics
Обобщённые типы в TypeScript
Цель урока
В этом уроке ты научишься:
- Создавать generic функции
- Использовать constraints
- Создавать generic интерфейсы и классы
Зачем нужны generics
// Без generics — теряем информацию о типе
function identity(value: any): any {
return value;
}
let result = identity("hello"); // тип: any
// С generics — сохраняем тип
function identity<T>(value: T): T {
return value;
}
let result = identity<string>("hello"); // тип: string
let result2 = identity(42); // тип: number (вывод)Generic функции
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
let num = first([1, 2, 3]); // number | undefined
let str = first(["a", "b"]); // string | undefined
// Несколько параметров
function pair<T, U>(a: T, b: U): [T, U] {
return [a, b];
}
let p = pair("hello", 42); // [string, number]Constraints
Ограничения на generic тип:
// T должен иметь свойство length
function logLength<T extends { length: number }>(value: T): void {
console.log(value.length);
}
logLength("hello"); // 5
logLength([1, 2, 3]); // 3
// logLength(123); // Ошибка!
// Ключи объекта
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let user = { name: "Иван", age: 25 };
let name = getProperty(user, "name"); // string
// getProperty(user, "email"); // Ошибка!Generic интерфейсы
interface Box<T> {
value: T;
}
let stringBox: Box<string> = { value: "hello" };
let numberBox: Box<number> = { value: 42 };
// С методами
interface Collection<T> {
items: T[];
add(item: T): void;
get(index: number): T;
}Generic классы
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
peek(): T | undefined {
return this.items[this.items.length - 1];
}
}
let numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
console.log(numberStack.pop()); // 2Значения по умолчанию
interface Response<T = any> {
data: T;
status: number;
}
let response1: Response = { data: "anything", status: 200 };
let response2: Response<{ name: string }> = {
data: { name: "Иван" },
status: 200
};Практические примеры
API Response
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchApi<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
return response.json();
}
interface User {
id: number;
name: string;
}
let users = await fetchApi<User[]>("/api/users");
// users.data имеет тип User[]Практика
Задание 1: Generic функция
Задача: Создай функцию last, возвращающую последний элемент.
Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
3 c
Задание 2: Generic интерфейс
Задача: Создай интерфейс для результата.
Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
Иван
Задание 3: Constraints
Задача: Создай функцию с constraint.
Запустите код для проверки
Loading...
Ваш вывод:
Ожидаемый результат:
{"a":1,"b":2}Проверь себя
- Зачем нужны generics?
- Что делает extends в generic?
- Как задать значение по умолчанию?