← Назад к вопросам

Можно ли заменить Enum на Union?

2.0 Middle🔥 192 комментариев
#JavaScript Core

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Замена Enum на Union Type в TypeScript

Да, в TypeScript Union Type часто является более предпочтительной и типобезопасной альтернативой enum, особенно в современных проектах. Это один из ключевых трендов в сообществе TypeScript за последние годы. Однако выбор зависит от конкретного контекста и требований проекта.

Сравнение подходов

Классический Enum

enum Status {
  Pending = 'PENDING',
  Approved = 'APPROVED',
  Rejected = 'REJECTED'
}

function processStatus(status: Status) {
  switch(status) {
    case Status.Pending: /* ... */ break;
    case Status.Approved: /* ... */ break;
  }
}

Union Type альтернатива

type Status = 'PENDING' | 'APPROVED' | 'REJECTED';

function processStatus(status: Status) {
  switch(status) {
    case 'PENDING': /* ... */ break;
    case 'APPROVED': /* ... */ break;
  }
}

Преимущества Union Types перед Enum

  1. Более простая типобезопасность

    • Union types предоставляют те же проверки типов без дополнительной runtime-сущности
    • Меньше boilerplate-кода
  2. Лучшая поддержка tree-shaking

    // Enum добавляет код в сборку даже если не используется
    enum Colors { Red, Green, Blue }
    
    // Union type полностью удаляется при tree-shaking
    type Colors = 'RED' | 'GREEN' | 'BLUE';
    
  3. Более прозрачная модель данных

    // С enum
    const status = Status.Approved; // Значение: 'APPROVED'
    
    // С union type - значение явное и предсказуемое
    const status: Status = 'APPROVED';
    
  4. Лучшая совместимость с JavaScript экосистемой

    • Union types используют native JavaScript строки/числа
    • Легче сериализовать/десериализовать
    • Совместимо с JSON без дополнительных преобразований
  5. Расширяемость и композиция

    type BasicStatus = 'PENDING' | 'APPROVED';
    type ExtendedStatus = BasicStatus | 'REJECTED' | 'CANCELLED';
    
    // Легко комбинировать типы
    type ApiResponse<T> = 
      | { status: 'SUCCESS'; data: T }
      | { status: 'ERROR'; message: string };
    

Когда всё же стоит использовать Enum

  1. Необходимость reverse mapping

    enum NumericEnum {
      Up = 1,
      Down = 2
    }
    
    const name = NumericEnum[1]; // "Up" - работает только с numeric enums
    
  2. Компактные числовые значения для протоколов/API

    enum BitFlags {
      Read = 1 << 0,
      Write = 1 << 1,
      Execute = 1 << 2
    }
    
  3. Сложные вычисляемые значения

    enum FileAccess {
      None = 0,
      Read = 1 << 0,
      Write = 1 << 1,
      ReadWrite = Read | Write
    }
    

Рекомендации по миграции

Для постепенного перехода можно использовать const enum как промежуточное решение:

const enum TransitionalStatus {
  Pending = 'PENDING',
  Approved = 'APPROVED'
}

// На этапе рефакторинга заменяем на:
type FinalStatus = 'PENDING' | 'APPROVED';

Лучшие практики в 2024+

  1. Для новых проектов — предпочитайте union types
  2. Для строковых перечислений — почти всегда используйте union types
  3. Для совместимости с external API — оцените необходимость обратного маппинга
  4. Для битовых флагов — рассмотрите использование enum с числовыми значениями

Вывод

Union Type в большинстве случаев является более современной, эффективной и типобезопасной заменой enum для строковых литералов. Они обеспечивают лучшую производительность сборки, большую гибкость и большую совместимость с JavaScript экосистемой. Однако enum сохраняет свою ценность в специфических сценариях, требующих обратного маппинга или сложных вычисляемых значений. Решение должно приниматься на основе конкретных требований проекта, учитывая долгосрочную поддерживаемость кода и производительность приложения.

Можно ли заменить Enum на Union? | PrepBro