Перейти к основному содержимому

Паттерны в TypeScript

Play ITЗагрузка интерактивного демо…

Разработчику Архитектору

Дальше: Дженерики · Обработка ошибок · Объекты и классы · Справочник — распространённые паттерны

Паттерны проектирования в TypeScript усиливаются типами: компилятор проверяет исчерпывающие switch, контракты фабрик и форму DTO. Ниже — приёмы, которые чаще всего встречаются в frontend и Node, без формального каталога GoF. Теория паттернов — парадигмы и уровни абстракции. Удобный порядок — типы и типизация, классы, эта статья, обработка ошибок. Таблицы — Справочник — распространённые паттерны.


Discriminated union (команды и состояния)

Код ITЗагрузка примера кода…

Разбор:

Применение — Redux actions, очереди сообщений, UI state — Асинхронное программирование в TypeScript, TypeScript и React.


Branded types (номинальность поверх structural)

type UserId = string & { readonly __brand: "UserId" };
type OrderId = string & { readonly __brand: "OrderId" };

function userId(raw: string): UserId {
return raw as UserId;
}

function loadOrder(id: OrderId): void {
console.log(id);
}

const u = userId("u-1");
loadOrder(u); // ошибка: OrderId ≠ UserId

Разбор:

  • Оба в runtime — string, но TS запрещает перепутать.
  • Валидацию формата (UUID) делайте в функции-конструкторе userId.

Factory по интерфейсу

Код ITЗагрузка примера кода…

Разбор:

  • Код зависит от Logger, без привязки к конкретному классу — проще тесты (mock).
  • Structural typing: любой объект с log подойдёт, если не нужна номинальность.

DTO + mapper между слоями

Код ITЗагрузка примера кода…

Разбор:

  • API (snake_case, string date) ≠ domain (Date).
  • Один mapper на границе — не размазывать преобразования — TypeScript и Node.js.

Type-safe event bus

Код ITЗагрузка примера кода…

Разбор:

  • K extends keyof Events связывает имя события и форму payload — тот же приём, что у updater: первый аргумент сужает второй.
  • Literal union в currency и role ловит опечатки и неверные коды до запуска.
  • В колбэке on доступны только поля выбранного события; деструктуризация чужого поля — ошибка компиляции.
  • В продакшене — typed wrappers над EventEmitter или фреймворк.
  • Тот же механизм PayloadMap[E] для отдельных handler-функций и констант as constдженерики §сопоставленные типы.

Builder с цепочкой

Код ITЗагрузка примера кода…

Разбор:

  • this return type сохраняет fluent API в подклассах.
  • Для SQL в продакшене — query builder библиотеки, без ручных строк.

Repository (интерфейс + реализация)

Код ITЗагрузка примера кода…

Связь с Объекты и классы в TypeScript, TypeORM.


Примеси (mixins)

В TypeScript нет ключевого слова mixin, но примесь — это функция, которая принимает класс-конструктор и возвращает расширенный класс. Так комбинируют поведение без глубокого наследования.

Код ITЗагрузка примера кода…

Разбор:

  • Timestamped и Identifiableпримеси; порядок обёртки влияет на цепочку super.
  • Типы параметров конструктора в реальных проектах сужают через Constructor и дженерики — Дженерики в TypeScript.
  • В React чаще используют композицию хуков; классовые mixins — реже. В Nest/ORM — декораторы и базовые классы — Декораторы в TypeScript.

Альтернатива примесям для объектов без классов: пересечение типов + spread ({ ...a, ...b }) или отдельные функции-хелперы — 18.md §композиция.


Anti-patterns

ПлохоЛучше
any на границе модуляunknown + mapper
Строковые коды ошибок без uniontype ErrorCode = "..." | "..."
God-object type на 50 полейразбить DTO / domain
as вездеguards, Zod
Дублировать union вручнуюas const + typeofТипы данных и типизация в TypeScript

Частые ошибки

ОшибкаЧто делать
Union без дискриминантадобавить поле type / kind
Забыли never в switchexhaustive check
Branded type без factoryодин вход userId()
Mapper в UI-компонентеслой api/ или mappers/

Практика

  1. Опишите 3 команды Command и handleCommand с never.
  2. Введите UserId / OrderId branded и поймайте ошибку присваивания.
  3. Сделайте fromDto / toDto для одной сущности.
  4. Добавьте TypedEmitter с двумя событиями.
  5. Вынесите Repository interface и in-memory реализацию.

Смежные статьи