Kodokon kodokon.com

Обобщения: простые дженерик-функции и типы

Пиши переиспользуемые функции и типы, которые сохраняют полную точность типов при каждом вызове.

9 мин · 3 вопросов

Открыть этот урок в Kodokon

Ты уже пользуешься обобщениями, сам того не замечая: string[], Promise<number>... Пора написать свои. Обобщение вводит параметр типа - переменную, которую при каждом использовании заменяет конкретный тип. Цель: написать логику один раз, не жертвуя точностью типов.

TYPESCRIPT
function first<T>(items: T[]): T | undefined {
  return items[0];
}

const n = first([10, 20, 30]);
const s = first(["a", "b"]);
T выводится сам: n - это number | undefined, s - это string | undefined

Заметь, что при вызове ты ничего не указал: TypeScript выводит T из аргумента. Обобщение без ограничений принимает что угодно, но функции часто нужен минимум гарантий о своих данных. Ключевое слово extends задаёт для T минимальную форму.

TYPESCRIPT
interface HasId {
  id: number;
}

function findById<T extends HasId>(
  items: T[],
  id: number
): T | undefined {
  return items.find((item) => item.id === id);
}
Ограничение: у T должен быть как минимум числовой id

Сами типы тоже могут быть обобщёнными. Это повседневность в сетевом коде: структура ответа стабильна, меняется лишь содержимое data. Один-единственный тип описывает тогда все ответы твоего API.

TYPESCRIPT
interface ApiResponse<T> {
  ok: boolean;
  data: T;
}

type UserResponse = ApiResponse<{ name: string }>;

const res: UserResponse = {
  ok: true,
  data: { name: "Ada" },
};
Обобщённый тип параметризует содержимое data

Проверка знаний

Убедись, что запомнил ключевые моменты этого урока.

  1. Что означает T в функции first<T>(items: T[]): T | undefined?
    • Конкретный тип, заданный раз и навсегда
    • Параметр типа, который заменяется при каждом вызове
    • Тип unknown
    • Сокращение для any
  2. Что гарантирует ограничение <T extends HasId>?
    • T - это в точности тип HasId
    • У T есть как минимум свойства HasId
    • T наследуется от класса HasId
  3. Ты вызываешь first([10, 20, 30]), не указывая тип. Чему равно T?
    • any
    • unknown
    • number
    • 10 | 20 | 30