Какие знаешь проблемы Enum

Ответ

Enums в TypeScript имеют несколько потенциальных проблем:

  1. Числовые enums могут быть небезопасными — они допускают невалидные значения:
enum Status {
  Active = 1,
  Inactive = 2
}
const s: Status = 999; // Ошибки не будет
  1. Обратное маппинг может сбивать с толку:
enum Color { Red = 1 }
console.log(Color[1]); // "Red" - не всегда ожидаемое поведение
  1. Tree-shaking — enums генерируют реальный код в runtime, что мешает удалению неиспользуемого кода.

  2. Строковые enums не поддерживают обратное маппинг вообще.

  3. Const enums решают проблему tree-shaking, но требуют preserveConstEnums и не работают в изолированных модулях.

Альтернатива — использовать union types:

type Status = 'active' | 'inactive';

Ответ 18+ 🔞

Слушай, давай разберём эту дичь с энамами в TypeScript, а то народ путается, как в тёмной комнате хуй искать.

Первое, что надо понять — числовые энамы это такая себе затея. Выглядит вроде прилично, объявил коды статусов, а под капотом-то пиздец. Допустим, сделали мы так:

enum Status {
  Active = 1,
  Inactive = 2
}

И вроде всё типобезопасно, ан нет! Какой-нибудь левый импорт или API может подсунуть тебе хуйню, и компилятор проглотит это, как манная каша.

const currentStatus: Status = 999; // И ни одной ошибки, ёпта!

Представляешь? Ты ждёшь 1 или 2, а тебе прилетает 999. Это как заказать пиццу, а тебе в коробке привозят дохлого хомяка — тип вроде еда, а нихуя не то.

Дальше — обратное маппирование. Это такая фишка, которая мозг выносит новичкам.

enum Color { Red = 1 }
console.log(Color[1]); // Выведет "Red"

С одной стороны, удобно. С другой — зачем? Это же чисто рантаймовая фигня, которая код раздувает. Ты хотел просто типы, а получил целый объект с ключами туда-сюда. Ёперный театр!

И вот это раздувание — третья проблема, tree-shaking. Энамы на выходе становятся реальными JavaScript-объектами. Если ты используешь только пару значений, весь enum всё равно попадёт в бандл. Мёртвый код не удаляется, как гандон прилипший.

Со строковыми энамами (enum Direction { Up = "UP" }) обратного маппинга вообще нет, что тоже иногда бесит.

Есть, конечно, const enum. Вот это вроде умная мысль — они полностью удаляются при компиляции, на их месте остаются только значения.

const enum Size { Small, Medium }
const mySize = Size.Small; // В JS станет просто `const mySize = 0;`

Но и тут, блядь, подвох! Чтобы они работали в изолированных модулях, нужно флаг preserveConstEnums или ещё какая-то магия. А без него — просто сломается всё, пидары налетели.

Так что же делать, если энамы такие проблемные? А альтернатива-то проще некуда, честное слово!

Используй union types из литералов:

type Status = 'active' | 'inactive';
type HttpCode = 200 | 404 | 500;

Смотри, какая красота:

  1. Никакого рантайм-кода — чистые типы, которые после компиляции испаряются.
  2. Полная типобезопасность — const s: Status = 'pending' вызовет ошибку, ибо 'pending' нет в разрешённых значениях. Никаких 999!
  3. Отлично дружит с tree-shaking — ничего лишнего в бандле.

Короче, если тебе не нужна именно рантаймовая структура (например, для итерации по всем значениям), забей на классические enum. Юнион типы — твой друг, товарищ и брат. Меньше головной боли, меньше неожиданностей. Всё гениальное — просто, а всё сложное — часто просто хуйня.