Урок 11

Enum и альтернативы

Enum — способ задать набор именованных значений. В TypeScript есть, но у него есть нюансы.

Числовой enum

    Idle,
    Loading,
    Success,
    Error,
}

let status: Status = Status.Idle;

По умолчанию Idle = 0, Loading = 1 и так далее.

С заданными значениями

    Idle = 1,
    Loading = 2,
    Success = 3,
}

Строковый enum

    Idle = 'idle',
    Loading = 'loading',
    Success = 'success',
}

let status: Status = Status.Idle;

Строковые enum безопаснее: значение читаемо в логах.

Константный enum

const enum Status {
    Idle = 'idle',
    Loading = 'loading',
}

Компилятор вставляет значения напрямую, без создания объекта. Быстрее, но есть ограничения.

Проблемы enum

Runtime-код

Обычный enum создаёт объект в рантайме. Это увеличивает бандл.

Несовместимость с erasableSyntaxOnly

Современный тренд — писать TypeScript, который компилируется в JS без дополнительного кода. enum этому противоречит.

Не работает с union

enum Status { Idle, Loading }

function handle(s: Status) {}
handle('idle'); // ошибка

Альтернатива: union литералов

type Status = 'idle' | 'loading' | 'success' | 'error';

let status: Status = 'idle';

Плюсы:

  • Нет runtime-кода
  • Совместимо с JSON
  • Работает везде
  • Проще

Альтернатива: объект as const

Если нужны и тип, и значения:

const Status = {
    Idle: 'idle',
    Loading: 'loading',
    Success: 'success',
} as const;

type Status = typeof Status[keyof typeof Status];
// 'idle' | 'loading' | 'success'

let status: Status = Status.Idle;

Плюсы:

  • Есть объект для итерации
  • Есть тип
  • Нет runtime-накладок

Когда enum оправдан

  • Проект старый, уже использует enum
  • Нужны reverse-mapping (числовой enum)
  • Команда привыкла к enum

Во всех новых проектах — union или as const.

Пример: замена enum

// Было
enum Role {
    Admin = 'admin',
    User = 'user',
}

function check(role: Role) {}

// Стало
type Role = 'admin' | 'user';

function check(role: Role) {}

Или:

const Role = {
    Admin: 'admin',
    User: 'user',
} as const;

type Role = typeof Role[keyof typeof Role];

Object.values(Role); // ['admin', 'user']

Итоги

  • Enum создаёт runtime-код
  • Строковые enum читаемы, числовые — компактны
  • Union литералов — современная альтернатива
  • as const + typeof — если нужен объект
  • В новых проектах enum не нужен