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

В чем разница между Enum и Union?

2.0 Middle🔥 151 комментариев
#TypeScript

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Разница между Enum и Union в TypeScript

Enum и Union Type - это два разных способа определить набор допустимых значений, но они работают по-разному и решают разные проблемы.

Enum - структура данных с именованными константами

Enum создает объект с именованными значениями:

enum Status {
  Active = 'ACTIVE',
  Inactive = 'INACTIVE',
  Pending = 'PENDING'
}

// Использование:
const userStatus: Status = Status.Active; // 'ACTIVE'
const otherStatus: Status = Status.Pending; // 'PENDING'

// Enum тоже создает объект в runtime:
console.log(Status.Active);      // 'ACTIVE'
console.log(Status['ACTIVE']);   // 'Active'
console.log(Object.keys(Status)); // ['Active', 'Inactive', 'Pending']

Компилируется в JavaScript:

var Status;
(function (Status) {
  Status["Active"] = "ACTIVE";
  Status["Inactive"] = "INACTIVE";
  Status["Pending"] = "PENDING";
})(Status || (Status = {}));

Union Type - тип, объединяющий несколько типов

Union определяет что переменная может быть одним из нескольких значений:

type Status = 'ACTIVE' | 'INACTIVE' | 'PENDING';

// Использование:
const userStatus: Status = 'ACTIVE';    // OK
const otherStatus: Status = 'PENDING';  // OK
const badStatus: Status = 'UNKNOWN';    // ERROR: Type '"UNKNOWN"' is not assignable to type 'Status'

Компилируется в пустоту (type erasure):

// Union Types полностью удаляются при компиляции в JavaScript
// Остается только значение
const userStatus = 'ACTIVE';
const otherStatus = 'PENDING';

Ключевые отличия

1. Runtime vs Compile-time

// ENUM - существует в runtime
enum Color {
  Red = 'RED',
  Green = 'GREEN'
}

function convertColor(c: Color): string {
  switch(c) {
    case Color.Red: return 'red';
    case Color.Green: return 'green';
  }
}

// Union Type - стирается в runtime
type Color = 'RED' | 'GREEN';

function convertColor(c: Color): string {
  switch(c) {
    case 'RED': return 'red';
    case 'GREEN': return 'green';
  }
}

2. Размер бундла

// Enum добавляет код в бандл
enum Status { Active, Inactive }
// Результат: ~200 байт JavaScript

// Union Type не добавляет ничего
type Status = 'ACTIVE' | 'INACTIVE';
// Результат: 0 байт (стирается)

3. Обратное отображение (Enum)

enum Color {
  Red = 'RED',
  Green = 'GREEN'
}

// Можешь получить ключ по значению
const key = Color['RED'];  // 'Red'

// С Union это невозможно без дополнительного кода
type Color = 'RED' | 'GREEN';
// Нет встроенного способа получить 'RED' -> 'Red'

4. Проверка типа

// Enum - можешь проверить в runtime
enum Status { Active = 'ACTIVE', Inactive = 'INACTIVE' }

function isValidStatus(value: any): value is Status {
  return Object.values(Status).includes(value);
}

isValidStatus('ACTIVE');  // true
isValidStatus('UNKNOWN'); // false

// Union - нужен более сложный type guard
type Status = 'ACTIVE' | 'INACTIVE';

function isValidStatus(value: any): value is Status {
  return value === 'ACTIVE' || value === 'INACTIVE';
}

// Или const assertion
const validStatuses = ['ACTIVE', 'INACTIVE'] as const;
type Status = typeof validStatuses[number];

Когда использовать что

Используй Union Type когда:

// 1. Просто типизация, нет нужды в runtime объекте
type UserRole = 'admin' | 'user' | 'guest';

// 2. Хочешь минимизировать бундл
// Union добавляет 0 байт

// 3. Данные приходят с API в виде строк
interface User {
  id: string;
  role: 'admin' | 'user' | 'guest';  // Приходит так с API
}

// 4. Хочешь простоту
type Status = 'pending' | 'success' | 'error';
const [status, setStatus] = useState<Status>('pending');

Используй Enum когда:

// 1. Нужны константы в runtime
enum HttpStatus {
  OK = 200,
  Created = 201,
  BadRequest = 400,
  Unauthorized = 401,
  NotFound = 404
}

function handleResponse(status: HttpStatus) {
  if (status === HttpStatus.OK) { ... }
}

// 2. Нужно обратное отображение
enum Color { Red = 'RED', Green = 'GREEN' }
const name = Color['RED'];  // Только для Enum

// 3. Нужна итерация по всем значениям
enum Role { Admin, User, Guest }
const roles = Object.values(Role);

// 4. Нужна валидация в runtime
function isValidRole(role: any): boolean {
  return Object.values(Role).includes(role);
}

Практические примеры

Пример 1: Статусы формы

// Union - лучший выбор
type FormStatus = 'idle' | 'loading' | 'success' | 'error';

const [status, setStatus] = useState<FormStatus>('idle');

if (status === 'loading') {
  return <Spinner />;
}

Пример 2: HTTP методы

// Union - простой и понятный
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';

const request = (url: string, method: HttpMethod) => {
  // ...
};

Пример 3: Ролевой контроль доступа

// Enum - хорош для сложной логики
enum Permission {
  Read = 1,
  Write = 2,
  Delete = 4
}

const userPermissions = Permission.Read | Permission.Write;
const canDelete = (userPermissions & Permission.Delete) !== 0;

Пример 4: Данные с сервера

// Union Type - берешь как приходит
interface ApiResponse {
  status: 'success' | 'error';
  message: string;
}

// vs Enum - преобразуешь
enum Status { Success = 'success', Error = 'error' }

const api = async (): Promise<Status> => {
  const response = await fetch('...');
  const data = await response.json();
  return data.status as Status;
};

Правило большого пальца

Union Type:
✓ Используй по умолчанию
✓ Меньше кода
✓ Меньше бундла
✓ Понятнее для большинства случаев

Enum:
✓ Используй если нужен объект в runtime
✓ Нужна проверка по Object.values()
✓ Нужны битовые операции или маски
✓ Сложная логика с константами

Лучшая практика: Union Type + Const Object

// Лучший подход - типизация + runtime константы
const STATUS = {
  ACTIVE: 'ACTIVE',
  INACTIVE: 'INACTIVE',
  PENDING: 'PENDING'
} as const;

type Status = typeof STATUS[keyof typeof STATUS];

// Получаешь:
// - Типизацию (Status type)
// - Runtime значения (STATUS объект)
// - Минимальный бундл
// - Безопасность от опечаток

const userStatus: Status = STATUS.ACTIVE;  // Типобезопасно
const allStatuses = Object.values(STATUS); // Итерация возможна

Заключение

Enum и Union Type решают разные проблемы:

  • Union Type - для типизации, меньше boilerplate, рекомендуется по умолчанию
  • Enum - когда нужен runtime объект и сложная логика

В современном TypeScript часто лучше использовать Union Type + const объект вместо Enum для баланса между типобезопасностью и производительностью.

В чем разница между Enum и Union? | PrepBro