Typescript Глубокое Погружение
  • Typescript Глубокое Погружение
  • Typescript проект
    • Контекст компиляции
    • Пространство декларации
    • Модули
    • Пространства имен
    • Динамический импорт выражений
  • Typescript Система типов
    • Обзор
    • Миграция с JavaScript
    • @types
    • Декларация окружения
    • Интерфейсы
    • Перечисления
    • lib.d.ts
    • Функции
    • Подлежащий выкупу
    • Тип утверждения
    • Freshness
    • Тип защиты
    • Литеральный тип
    • readonly
    • Дженерики
    • Тип вывода
    • Тип совместимости
Powered by GitBook
On this page
  • Числовые перечисления и числа
  • Числовые перечисления и строки
  • Изменить число, связанное с числовым перечислением
  • Числовые перечисления как флаги
  • Перечисления строк
  • Постоянное перечисление
  • Опция preserveConstEnums
  • Перечисление со статическими методами
  • Перечисления открыты для добавления

Was this helpful?

  1. Typescript Система типов

Перечисления

Перечисление - это способ организации коллекции связанных переменных. Многие языки программирования (такие как С / С# / Java) имеют тип данных enum. Вот как определить тип перечисления в TypeScript:

enum CardSuit {
  Clubs,
  Diamonds,
  Hearts,
  Spades
}

// Простое использование перечислимых типов
let Card = CardSuit.Clubs;

// Проверка безопасности
Card = 'not a member of card suit'; // Error : string is not assignable to type `CardSuit`

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

Числовые перечисления и числа

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

enum Color {
  Red,
  Green,
  Blue
}

let col = Color.Red;
col = 0; // Тоже самое что и Color.Red

Числовые перечисления и строки

Прежде чем мы углубимся в перечисления, давайте рассмотрим генерируемый им JavaScript, вот пример TypeScript:

enum Tristate {
    False,
    True,
    Unknown
}

Скомпилированный JavaScript:

var Tristate;
(function (Tristate) {
    Tristate[Tristate["False"] = 0] = "False";
    Tristate[Tristate["True"] = 1] = "True";
    Tristate[Tristate["Unknown"] = 2] = "Unknown";
})(Tristate || (Tristate = {}));

давайте сосредоточимся на строке Tristate [Tristate['False'] = 0] = 'False' ;. Внутри него Tristate ['False'] = 0 должен быть самоочевидным, т. e. присваивает элементу False переменной Tristate значение 0. Обратите внимание, что в JavaScript оператор присваивания возвращает назначенное значение (в данном случае 0). Поэтому следующая вещь, выполняемая средой выполнения JavaScript, это Tristate[0] = 'False'. Это означает, что вы можете использовать переменную Tristate для преобразования строковой версии перечисления в число или числовую версию перечисления в строку. Это продемонстрировано ниже:

enum Tristate {
  False,
  True,
  Unknown
}

console.log(Tristate[0]); // 'False'
console.log(Tristate['False']); // 0
console.log(Tristate[Tristate.False]); // 'False' because `Tristate.False == 0`

Изменить число, связанное с числовым перечислением

По умолчанию первое значение перечисления равно 0, а каждое последующее значение увеличивается на единицу:

enum Color {
  Red, // 0
  Green, // 1
  Blue // 2
}

Однако вы можете изменить число, связанное с любым членом перечисления, с помощью специального назначения. Для следующего примера мы увеличиваем с 3:

enum Color {
  DarkRed = 3, // 3
  DarkGreen, // 4
  DarkBlue // 5
}

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

Числовые перечисления как флаги

Одним из превосходных применений перечислений является возможность использовать перечисления в качестве флагов. Флаги позволяют вам проверить, верно ли определенное условие из набора условий. Рассмотрим следующий пример, где у нас есть набор свойств о животных:

enum AnimalFlags {
  None        = 0,
  HasClaws    = 1 << 0,
  CanFly      = 1 << 1,
  EatsFish    = 1 << 2,
  Endangered  = 1 << 3
}

Здесь мы используем оператор побитового сдвига влево, чтобы сдвинуть двоичную позицию числа 1 влево, и получить числа 0001, 0010, 0100 и 1000 (в десятичных терминах: 1, 2, 4, 8). Когда вы используете этот флаг, ваши битовые операторы | (или), & (и), ~ (нет) не при работе с флагами:

enum AnimalFlags {
  None        = 0,
  HasClaws    = 1 << 0,
  CanFly      = 1 << 1
}

interface Animal {
  flags: AnimalFlags;
  [key: string]: any;
}

function printAnimalAbilities(animal: Animal) {
  var animalFlags = animal.flags;
  if (animalFlags & AnimalFlags.HasClaws) {
    console.log('animal has claws');
  }
  if (animalFlags & AnimalFlags.CanFly) {
    console.log('animal can fly');
  }
  if (animalFlags == AnimalFlags.None) {
    console.log('nothing');
  }
}

var animal = { flags: AnimalFlags.None };
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws;
printAnimalAbilities(animal); // animal has claws
animal.flags &= ~AnimalFlags.HasClaws;
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly;
printAnimalAbilities(animal); // animal has claws, animal can fly

Здесь:

  • Мы использовали |=, чтобы добавить флаги;

  • комбинацию &= и ~, чтобы убрать флаг;

  • | объединить флаги.

Вы можете комбинировать флаги для определения удобных и быстрых способов в перечисляемых типах следующим образом EndangeredFlyingClawedFishEating:

enum AnimalFlags {
  None        = 0,
  HasClaws    = 1 << 0,
  CanFly      = 1 << 1,

  EndangeredFlyingClawedFishEating = HasClaws | CanFly | EatsFish | Endangered
}

Перечисления строк

Мы смотрели только на перечисления, где значения членов являются числами. На самом деле вам также разрешено иметь члены перечисления со строковыми значениями. Например:

export enum EvidenceTypeEnum {
  UNKNOWN = '',
  PASSPORT_VISA = 'passport_visa',
  PASSPORT = 'passport',
  SIGHTED_STUDENT_CARD = 'sighted_tertiary_edu_id',
  SIGHTED_KEYPASS_CARD = 'sighted_keypass_card',
  SIGHTED_PROOF_OF_AGE_CARD = 'sighted_proof_of_age_card'
}

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

Вы можете использовать эти значения для простого сравнения строк. Например:

// Where `someStringFromBackend` will be '' | 'passport_visa' | 'passport' ... etc.
const value = someStringFromBackend as EvidenceTypeEnum;

// Sample use in code
if (value === EvidenceTypeEnum.PASSPORT) {
  console.log('You provided a passport');
  console.log(value); // `passport`
}

Постоянное перечисление

enum Tristate {
  False,
  True,
  Unknown
}

const lie = Tristate.False;

Строка const lie = Tristate.False скомпилируется в const lie = Tristate.False (да, выходные данные совпадают с входными данными). Это означает, что во время выполнения необходимо будет выполнить поиск Tristate, а затем Tristate.False. Для повышения производительности вы можете пометить перечисление как постоянное перечисление(const enum). Это продемонстрировано ниже:

const enum Tristate {
  False,
  True,
  Unknown
}

const lie = Tristate.False;

Будет скомпилировано в:

var lie = 0;

Компилятор будет:

  • Любое использование встроенных перечислений (0 вместо Tristate.False);

  • Не генерирует JavaScript для определения enum (во время выполнения отсутствует переменная Tristate), поскольку его использование встроено.

Опция preserveConstEnums

Встраивание имеет очевидные преимущества в производительности. Тот факт, что во время выполнения отсутствует переменная Tristate, просто помогает компилятору, не генерировать JavaScript, который фактически не используется во время выполнения. Однако вы, возможно, захотите, чтобы компилятор по-прежнему генерировал JavaScript-версию определения перечисления для таких вещей, как получения числа через строку или поиск строки через число, как мы видели. В этом случае вы можете использовать флаг компилятора --preserveConstEnums, и он все равно сгенерирует определение var Tristate, так что вы можете использовать Tristate['False'] или Tristate[0] вручную во время выполнения, если хотите. Это никак не влияет на врезку.

Перечисление со статическими методами

Вы можете добавить статические методы к типам enum, используя объявление enum + namespace. Как показано в следующем примере, мы добавляем статический метод isBusinessDay в перечисление:

enum Weekday {
  Monday,
  Tuseday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

namespace Weekday {
  export function isBusinessDay(day: Weekday) {
    switch (day) {
      case Weekday.Saturday:
      case Weekday.Sunday:
        return false;
      default:
        return true;
    }
  }
}

const mon = Weekday.Monday;
const sun = Weekday.Sunday;

console.log(Weekday.isBusinessDay(mon)); // true
console.log(Weekday.isBusinessDay(sun));

Перечисления открыты для добавления

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

Давайте еще раз посмотрим, как выглядит перечисление, скомпилированное в JavaScript:

var Tristate;
(function(Tristate) {
  Tristate[(Tristate['False'] = 0)] = 'False';
  Tristate[(Tristate['True'] = 1)] = 'True';
  Tristate[(Tristate['Unknown'] = 2)] = 'Unknown';
})(Tristate || (Tristate = {}));

Мы объяснили что Tristate [Tristate ['False'] = 0] = 'False', теперь давайте посмотрим на функцию-оболочку (function (Tristate) {/ код здесь /}) (Tristate || (Tristate = { })), Особенно на часть (Tristate || (Tristate = {})). Он захватывает локальную переменную Tristate, которая либо указывает на уже существующее значение Tristate, либо инициализирует его новым пустым объектом.

Это означает, что вы можете разделить (и расширить) определение перечисления на несколько файлов, как показано ниже, вы можете разделить определение Color на два блока:

enum Color {
  Red,
  Green,
  Blue
}

enum Color {
  DarkRed = 3,
  DarkGreen,
  DarkBlue
}

Вы должны задать числовое значение первому члену в блоке продолжения перечисления, чтобы оно не перезатерло предыдущие значения. TypeScript выдаст предупреждение, если вы определите начальное значение (сообщение об ошибке: In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element.).

PreviousИнтерфейсыNextlib.d.ts

Last updated 5 years ago

Was this helpful?