0Pricing
TypeScript Academy · Урок

Размеченные объединения для безопасного сопоставления с шаблонами

Добавляйте общее поле-литерал к элементам объединения для безопасности типов

«Размеченные объединения для безопасного сопоставления с шаблонами» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.

Добро пожаловать

Дискриминируемые объединения добавляют общее литеральное свойство к вариантам объединения. TypeScript использует этот дискриминатор для сужения типа в операторах switch и if.

Свойство-дискриминатор

Дискриминатор — это свойство с уникальным литеральным типом в каждом варианте объединения. TypeScript сужает объединение на основе его значения.
type Circle = { kind: 'circle'; radius: number };
type Square = { kind: 'square'; side: number };
type Shape = Circle | Square;

Сужение с помощью проверок if

Проверьте дискриминатор в условии if. TypeScript сузит тип до соответствующего варианта.
function area(shape: Shape): number {
  if (shape.kind === 'circle') {
    return Math.PI * shape.radius ** 2;
  }
  return shape.side ** 2; // narrowed to Square
}

Сужение с помощью switch/case

Операторы switch отлично работают с дискриминируемыми объединениями. Каждый вариант case сужает тип до конкретного варианта.
function describe(shape: Shape): string {
  switch (shape.kind) {
    case 'circle': return `Circle r=${shape.radius}`;
    case 'square': return `Square s=${shape.side}`;
  }
}

Проверка полноты с типом без значений

Добавьте вариант default, присваивающий значение `never`. Если вы добавите новый вариант объединения и забудете его обработать, TypeScript сообщит об ошибке.
function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'square': return shape.side ** 2;
    default:
      const _exhaustive: never = shape;
      throw new Error('Unhandled shape');
  }
}

Шаблон результата

Дискриминируемые объединения идеально подходят для шаблона результата — возврата либо данных об успешном выполнении, либо ошибки без выбрасывания исключения.
type Ok<T> = { ok: true; value: T };
type Err = { ok: false; error: string };
type Result<T> = Ok<T> | Err;

Шаблон типа действия в стиле Redux

В Redux и подобных системах действия являются дискриминируемыми объединениями. Поле `type` — это дискриминатор.
type Action =
  | { type: 'INCREMENT'; amount: number }
  | { type: 'DECREMENT'; amount: number }
  | { type: 'RESET' };

Несколько свойств-дискриминаторов

Дискриминатор не обязан быть одним свойством — TypeScript может сужать тип на основе любой комбинации проверок.
type AdminUser = { role: 'admin'; permissions: string[] };
type RegularUser = { role: 'user'; credits: number };
type User = AdminUser | RegularUser;

Недискриминируемые объединения тоже сужаются

Даже без дискриминатора TypeScript сужает объединения с помощью typeof, instanceof и проверок свойств.
type StringOrArr = string | string[];
function flatten(val: StringOrArr): string[] {
  return Array.isArray(val) ? val : [val];
}

Дискриминируемые объединения и иерархии классов

Дискриминируемые объединения — это функциональная альтернатива наследованию классов для моделирования вариантов. Они проще, сериализуемы и хорошо работают с сопоставлением с образцом.

Практический пример: объединение ответов HTTP

Моделируйте разные состояния ответа API как дискриминируемое объединение.
type ApiState<T> =
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; message: string };

Быстрая проверка

Что должен иметь каждый вариант дискриминируемого объединения, чтобы TypeScript правильно выполнял сужение?

Повторение

Дискриминируемые объединения используют общее литеральное свойство как дискриминатор. Выполняйте сужение с помощью switch/case и добавляйте проверку полноты с `never`, чтобы обнаруживать необработанные варианты. Они идеально подходят для автоматов состояний, действий и ответов API.

Часто задаваемые вопросы

Урок «Размеченные объединения для безопасного сопоставления с шаблонами» бесплатный?

Да — полный текст урока «Размеченные объединения для безопасного сопоставления с шаблонами» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.

Чему я научусь в уроке «Размеченные объединения для безопасного сопоставления с шаблонами»?

Добавляйте общее поле-литерал к элементам объединения для безопасности типов Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать TypeScript Academy?

Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Размеченные объединения для безопасного сопоставления с шаблонами»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке TypeScript Academy?

Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Объединения типов: A или B
  2. Пересечения типов: A и B
  3. Размеченные объединения для безопасного сопоставления с шаблонами
  4. Практические шаблоны с объединениями и пересечениями
← Назад к TypeScript Academy