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

Перечисления (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
Автор
Редакция

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

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство