Гид по технологиям

Перечисления (enum) в TypeScript — руководство и лучшие практики

7 min read TypeScript Обновлено 31 Dec 2025
Enum в TypeScript: руководство и примеры
Enum в TypeScript: руководство и примеры

Крупный план чёрных клавиш печатной машинки

Введение

Enum (перечисление) — это структура данных, позволяющая определить набор именованных значений. Она помогает делать код более выразительным и самодокументированным: вместо «магических» чисел или строк вы используете понятные имена.

Короткое определение: enum — именованный набор констант, каждая из которых имеет ключ (строка) и значение (число, строка или вычисляемое выражение).

Важно: имя enum обычно пишут с заглавной буквы по соглашениям JavaScript/TypeScript.

Создание перечисления

Обычно перечисление описывает ограниченное множество вариантов. Например, перечисление для направлений или статусов.

Общий синтаксис в TypeScript:

enum Direction {
  Up,
  Down,
  Left,
  Right
}

Если явно не указывать значения, TypeScript автоматически присвоит числовые значения: первый член получит 0, следующий — 1 и так далее.

Явное присвоение:

enum Direction {
  Up = 0,
  Down = 1,
  Left = 2,
  Right = 3,
}

Частичное явное присвоение — значение после инициализированного члена продолжит автоинкремент:

enum Status {
  Active = 9,
  Inactive, // 10
}

Это поведение применяется только к числовым членам, не к строковым.

Типы перечислений

Enums в TypeScript можно условно разделить на три вида:

  • числовые (numeric enums)
  • строковые (string enums)
  • смешанные (heterogeneous enums)

Числовые перечисления

Это поведение, которое мы показали выше: члены получают числовые значения и могут автоматически инкрементироваться.

Пример:

enum Weekday {
  Monday = 1,
  Tuesday,
  Wednesday,
  Thursday,
  Friday
}

Строковые перечисления

Если все члены — строки, их нужно инициализировать явно. Это удобно при сериализации и логировании:

enum PrimaryColors {
  Red = "RED",
  Yellow = "YELLOW",
  Blue = "BLUE"
}

Строковые значения более самодоказывающие и часто предпочтительнее в API.

Смешанные перечисления

Смешанные enum содержат и строковые, и числовые члены:

enum Result {
  Success = "SUCCESS",
  Failure = 0
}

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

Константные и вычисляемые члены

Каждый член enum может быть константным или вычисляемым.

Коротко:

  • Константный член вычисляется на этапе компиляции.
  • Вычисляемый член определяется выражением, которое будет выполнено в рантайме.

Когда член считается константным

Член enum считается константным, если он удовлетворяет одному из условий:

  • это первый член и у него нет инициализатора;
  • он не имеет инициализатора, а предыдущий член был числовой константой;
  • он инициализирован с помощью константного выражения (строковый или числовой литерал, либо выражение, которое может быть вычислено на этапе компиляции).

Примеры константных enum:

// CASE 1
enum Direction {
  Up,
  Down,
  Left,
  Right
}

// CASE 2
enum Weekday {
  Monday = 1,
  Tuesday,
  Wednesday,
  Thursday,
  Friday
}

// CASE 3
enum Season {
  Spring = "SPRING",
  Summer = "SUMMER",
  Autumn = "AUTUMN",
  Winter = "WINTER"
}

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

Пример транспиляции для Season:

var Season;
(function (Season) {
    Season["Spring"] = "SPRING";
    Season["Summer"] = "SUMMER";
    Season["Autumn"] = "AUTUMN";
    Season["Winter"] = "WINTER";
})(Season || (Season = {}));

Вычисляемые члены

Если значение члена задаётся результатом функции или выражения, оно будет вычислено в рантайме:

enum Size {
  Small = 1,
  Medium = calculateSize(12),
  Large = calculateSize(5)
}

function calculateSize(value: number): number {
  return value * 5;
}

console.log(Size.Large);

Транспилированный код сохраняет вызов функции, поэтому конечные значения определяются уже в JavaScript во время выполнения:

var Size;
(function (Size) {
    Size[Size["Small"] = 1] = "Small";
    Size[Size["Medium"] = calculateSize(12)] = "Medium";
    Size[Size["Large"] = calculateSize(5)] = "Large";
})(Size || (Size = {}));

console.log(Size.Large);

Последний пример подчёркивает: вычисляемые члены увеличивают вероятность ошибок времени выполнения и усложняют статический анализ.

Доступ к значениям и обратная проекция

Доступ к членам enum осуществляется через точечную нотацию:

enum Direction {
  Up = 0,
  Down = 1,
  Left = 2,
  Right = 3,
}

console.log(Direction.Left); // 2

Обратная проекция для числовых enum

Числовые enum поддерживают обратную проекцию: можно получить имя члена по его значению. Это удобно при декодировании числовых состояний:

enum Direction {
  Up = 1,
  Down,
  Left,
  Right
}

function getDirectionName(directionValue: number): string {
  const directionName = Direction[directionValue];
  return directionName;
}

console.log(getDirectionName(1)); // "Up"
console.log(getDirectionName(3)); // "Left"

Обратной проекции нет для строковых enum — там нужно делать поиск через ключи или маппинг.

Когда использовать enum и альтернативы

Enum полезны, когда у вас есть ограниченный набор вариантов, и вы хотите:

  • улучшить читаемость кода;
  • централизовать значения для переключателей (switch) и условий;
  • сохранить согласованность API и сериализации.

Альтернативы enum:

  • union типов строк: type Status = “active” | “inactive”; — компиляция лучше, меньше кода в рантайме;
  • const objects: const Status = { Active: “ACTIVE” } as const; type Status = typeof Status[keyof typeof Status]; — даёт автодополнение и более компактный рантайм;
  • библиотеки с перечислениями/флагами, если нужны дополнительные механизмы сериализации/валидции.

Пример union типа:

type Status = "ACTIVE" | "INACTIVE";
function setStatus(s: Status) { /* ... */ }

Преимущество union: меньше магии рантайма, лучше оптимизируется и проще сериализуется.

Практические рекомендации

  • Предпочитайте строковые enum или union типов для публичных API и сериализации.
  • Избегайте смешанных enum, если нет острой нужды.
  • Минимизируйте вычисляемые члены — они усложняют анализ и тестирование.
  • Для производительности используйте const enum, если проект и сборка позволяют.

Примечание об использовании const enum:

const enum — специальная форма, которая полностью инлайнится при компиляции, но требует включённой опции компилятора и невозможности рефлексии на рантайме.

Миграция и совместимость

Если вы мигрируете с JavaScript или с plain objects на enum:

  1. Оцените, нужна ли обратная проекция: если да — используйте числовой enum.
  2. Если важна читаемость и API — используйте строковые значения или union типов.
  3. Проведите тесты сериализации/десериализации и интеграционные тесты.

Короткие советы:

  • при использовании библиотек сериализации (JSON, protobuf) отдавайте предпочтение строкам;
  • при взаимодействии с базами данных старайтесь хранить значения, удобные для чтения и миграции.

Контроль качества: чек-лист перед ревью

  • Является ли набор значений фиксированным?
  • Подходит ли строковый enum или union для API?
  • Нет ли вычисляемых членов без необходимости?
  • Не использован ли смешанный enum, где можно обойтись одним типом?
  • Обработана ли сериализация/десериализация в тестах?

Мини-методология для выбора типа enum

  1. Определите требования: нужен ли индентификатор (число) или человекочитаемое значение (строка).
  2. Если нужен компактный рантайм и обратная проекция — выберите числовой enum.
  3. Для API и логов — строковый enum или union типов.
  4. Если важно ноль-копий в рантайме — рассмотрите const enum и проверьте сборку.

Дерево решений (Mermaid)

graph TD
  A[Нужно ли обратное отображение по значению?] -->|Да| B[Числовой enum]
  A -->|Нет| C[Нужно ли человекочитаемое значение в API?]
  C -->|Да| D[Строковый enum или union типов]
  C -->|Нет| E[const enum или объекты с as const]

Роль‑ориентированные чек-листы

  • Для разработчика:

    • использовать понятные имена членов;
    • избегать магических чисел вне enum;
    • написать модульные тесты на сериализацию.
  • Для ревьювера:

    • проверить необходимость enum vs union;
    • оценить влияние на bundle size;
    • убедиться в корректной обработке ошибок при неизвестных значениях.
  • Для архитектора:

    • стандартизировать формат enum в кодовой базе (строки vs числа);
    • задокументировать рекомендации для API.

Критерии приёмки

  • Код использует enum только там, где набор значений фиксирован и документирован.
  • Все публичные API используют человекочитаемые значения (строки) или ясно задокументированы.
  • Нет неинициализированных вычисляемых членов без тестов.
  • Сборка и тесты не ломаются при включении const enum.

Частые ошибки и когда enum не работает

  • Использование смешанных enum для простых наборов значений — приводит к путанице.
  • Полагаться на вычисляемые значения в рантайме там, где нужен статический анализ.
  • Не тестировать сериализацию/десериализацию при изменении значений enum.

Короткий глоссарий

  • enum: перечисление именованных констант.
  • константный член: значение, вычисляемое на этапе компиляции.
  • вычисляемый член: значение, вычисляемое в рантайме.
  • обратная проекция: получение имени члена по его числовому значению.

Примеры тест-кейсов

  • Проверка, что Direction.Left === 2 при определённых значениях.
  • Проверка сериализации/десериализации строковых enum.
  • Тест на поведение при передаче неизвестного числового значения в функцию, делающую обратную проекцию.

Риски и смягчение

  • Риск: изменение числовых значений сломает клиентов. Смягчение: использовать строки в публичных API.
  • Риск: вычисляемые члены добавляют ошибки рантайма. Смягчение: избегать вычисляемых членов без тестов.

Заключение

Перечисления в TypeScript — мощный инструмент для выражения фиксированных наборов значений. Правильный выбор между числовыми и строковыми enum, осторожность с вычисляемыми и смешанными членами, а также стандартизация практик в проекте помогут сохранить читаемость, безопасность и совместимость кода.

Важно: перед принятием решения оцените последствия для API, bundle size и тестируемости.

Полезное напоминание:

Important: если требуется совместимость с внешними системами или человекочитаемость логов — выбирайте строковые значения или union типов.

Notes: const enum инлайнится компилятором и экономит место, но исключает возможности рефлексии.


FAQ

Что лучше для API: enum или union типов?

Для внешних API обычно лучше использовать строковые enum или union типов (например, type Status = “ACTIVE” | “INACTIVE”), потому что строки проще отлаживать и безопаснее при изменениях.

Можно ли использовать enum в JSON при передаче данных в сеть?

Да, но предпочтительнее использовать строковые enum или вручную сериализовать числовые enum в понятные строки, чтобы не ломать клиентов при изменении значений.

Что такое const enum и когда его применять?

const enum — это enum, который полностью инлайнится в финальный код при компиляции. Применяйте его для уменьшения размера бандла, если не нужна динамическая рефлексия по enum.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Группы вкладок Safari на iPhone и iPad
iOS

Группы вкладок Safari на iPhone и iPad

Как принудительно завершить приложение на Mac
macOS

Как принудительно завершить приложение на Mac

Как отправлять вкладки Chrome между устройствами
Chrome

Как отправлять вкладки Chrome между устройствами

Настройка стартовой страницы Safari на Mac
macOS

Настройка стартовой страницы Safari на Mac

Профили в Safari на iPhone и iPad — настройка
iOS

Профили в Safari на iPhone и iPad — настройка

Как управлять закладками и Избранным в Safari
браузер

Как управлять закладками и Избранным в Safari