Skip to content

Основы TypeScript: Перечисления (Enums)

Перечисления (enums) в TypeScript — это тип данных, который позволяет определить набор именованных констант. Они используются для представления набора связанных значений, которым присваиваются символические имена. Перечисления делают код более читаемым и облегчают работу с наборами констант.

Числовые перечисления (Numeric Enums)

По умолчанию, если вы не присваиваете значения элементам перечисления, TypeScript автоматически присваивает им числовые значения, начиная с 0 и увеличиваясь на единицу для каждого следующего элемента.

typescript
enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right, // 3
}

let move: Direction = Direction.Up;
console.log(move); // Выведет 0

if (move === Direction.Up) {
  console.log("Двигаемся вверх"); // Это будет выполнено
}

Вы можете явно присвоить числовые значения элементам перечисления. Если вы присваиваете значение только некоторым элементам, элементы, следующие за ними, будут автоматически инкрементироваться, начиная с присвоенного значения.

typescript
enum Status {
  Pending = 10,
  Approved, // 11
  Rejected = 20,
  Canceled, // 21
}

let currentStatus: Status = Status.Approved;
console.log(currentStatus); // Выведет 11

if (currentStatus === Status.Rejected) {
  console.log("Заявка отклонена");
} else if (currentStatus === Status.Approved) {
  console.log("Заявка одобрена"); // Это будет выполнено
}

Обратное сопоставление (Reverse Mapping)

Для числовых перечислений TypeScript генерирует обратное сопоставление. Это означает, что вы можете получить имя элемента перечисления по его числовому значению.

typescript
enum ResponseCode {
  OK = 200,
  NotFound = 404,
  InternalServerError = 500,
}

console.log(ResponseCode.OK); // Выведет 200
console.log(ResponseCode[200]); // Выведет "OK"

Обратное сопоставление создается только для числовых перечислений (где значения являются числами).

Строковые перечисления (String Enums)

В строковых перечислениях каждому элементу должно быть явно присвоено строковое значение. В отличие от числовых перечислений, строковые перечисления не поддерживают обратное сопоставление.

typescript
enum LogLevel {
  Debug = "DEBUG",
  Info = "INFO",
  Warning = "WARNING",
  Error = "ERROR",
}

let currentLevel: LogLevel = LogLevel.Info;
console.log(currentLevel); // Выведет "INFO"

if (currentLevel === LogLevel.Error) {
  console.log("Произошла ошибка!");
}

Гетерогенные перечисления (Heterogeneous Enums)

Гетерогенные перечисления содержат элементы с разными типами значений (числовыми и строковыми). Однако их использование не рекомендуется, так как они могут привести к непредсказуемому поведению и усложняют понимание кода.

typescript
enum Mixed {
  A,       // 0
  B = "B",
  C = 10,
  D,       // 11
}

console.log(Mixed.A); // 0
console.log(Mixed.B); // "B"
console.log(Mixed.C); // 10
console.log(Mixed.D); // 11
console.log(Mixed[0]); // "A"
// console.log(Mixed["B"]); // Ошибка: Элемент "B" не имеет числового значения, поэтому обратное сопоставление не работает
console.log(Mixed[10]); // "C"
console.log(Mixed[11]); // "D"

Обратите внимание, что обратное сопоставление работает только для числовых элементов гетерогенного перечисления.

Перечисления с константными выражениями (Enum with Constant Expressions)

Значения элементов перечисления могут быть константными выражениями, которые вычисляются во время компиляции.

typescript
const START_VALUE = 100;

enum StatusCode {
  OK = 200,
  Redirect = 300 + 1,
  NotFound = START_VALUE + 4,
}

console.log(StatusCode.OK);       // 200
console.log(StatusCode.Redirect); // 301
console.log(StatusCode.NotFound); // 104

Константные перечисления (Const Enums)

Константные перечисления объявляются с использованием ключевого слова const. В отличие от обычных перечислений, константные перечисления не создают объект во время выполнения. Вместо этого, значения элементов константного перечисления подставляются непосредственно в местах их использования в коде. Это может привести к уменьшению размера JavaScript-бандла.

typescript
const enum Operation {
  Add,
  Subtract,
  Multiply,
}

function calculate(a: number, b: number, op: Operation): number {
  switch (op) {
    case Operation.Add:
      return a + b;
    case Operation.Subtract:
      return a - b;
    case Operation.Multiply:
      return a * b;
  }
}

let result = calculate(5, 3, Operation.Multiply);
console.log(result); // Выведет 15

При компиляции код будет выглядеть примерно так (в зависимости от настроек компилятора):

javascript
function calculate(a, b, op) {
  switch (op) {
    case 0 /* Add */:
      return a + b;
    case 1 /* Subtract */:
      return a - b;
    case 2 /* Multiply */:
      return a * b;
  }
}
var result = calculate(5, 3, 2 /* Multiply */);
console.log(result);

Обратите внимание, что объект Operation не существует во время выполнения. Из-за этого вы не сможете получить имя элемента константного перечисления по его значению (нет обратного сопоставления).

Использование перечислений

Перечисления полезны в ситуациях, когда у вас есть набор именованных констант, которые логически связаны друг с другом. Они улучшают читаемость кода по сравнению с использованием "магических чисел" или строковых литералов.

Примеры использования перечислений:

  • Представление состояний (например, Loading, Success, Error).
  • Определение набора действий (например, Create, Read, Update, Delete).
  • Перечисление направлений (например, Up, Down, Left, Right).
  • Определение уровней логирования (например, Debug, Info, Warning, Error).

Заключение

Перечисления в TypeScript предоставляют удобный способ работы с наборами именованных констант. Они могут быть числовыми или строковыми, и TypeScript предоставляет различные возможности для их определения и использования. Выбор между обычными и константными перечислениями зависит от ваших потребностей в обратном сопоставлении и размере генерируемого JavaScript-кода. Правильное использование перечислений может сделать ваш код более понятным, поддерживаемым и типобезопасным.