Spec-Zone.ru › Flow

Определение перечислений

Узнайте, как определять перечисление Flow. Нужен краткий обзор? Ознакомьтесь с кратким руководством.

Объявление перечисления — это инструкция. Его имя задаёт и значение (для доступа к его элементам и вызова его методов), и тип (который можно использовать как аннотацию типа его элементов).

Все элементы перечисления должны иметь один и тот же тип. Они могут быть одного из пяти типов: строкового, числового, логического, bigint и symbol.

У всех перечислений есть несколько общих свойств:

Единый тип элементов​

Тип элементов перечисления должен быть единым. Например, нельзя смешивать элементы string и number в одном перечислении. Все они должны быть строками, числами, логическими значениями или значениями bigint (для перечислений на основе symbol значения не указываются).

Начальный символ имени элемента​

Имена элементов должны быть допустимыми идентификаторами (например, не начинаться с цифры) и не должны начинаться со строчных букв от a до z. Имена, начинающиеся с этих букв, зарезервированы для методов перечисления (например, Status.cast(...)).

Следующий вариант недопустим:

enum Status {
  active, // Error: names can't start with lowercase 'a' through 'z'
}

Уникальные имена элементов​

Имена элементов должны быть уникальными. Следующий вариант недопустим:

enum Status {
  Active,
  Active, // Error: the name 'Active' was already used above
}

Литеральные значения элементов​

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

enum Status {
  Active = 1 + 2, // Error: the value must be a literal
}

Уникальные значения элементов​

Значения элементов должны быть уникальными. Следующий вариант недопустим:

enum Status {
  Active = 1,
  Paused = 1, // Error: the value has already been used above
}

Фиксируются при объявлении​

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

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

По умолчанию перечисления являются строковыми. Если не указать предложение of (например, enum Status of number {}, enum Status of symbol {} и т. д.) и не указать значения (например, enum Status {Active = 1}), определение по умолчанию будет строковым перечислением.

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

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

enum Status {
  Active,
  Paused,
  Off,
}

Это то же самое, что:

enum Status {
  Active = 'Active',
  Paused = 'Paused',
  Off = 'Off',
}

Необходимо либо указать значения для всех элементов, либо не указывать их ни для одного. Следующий вариант недопустим:

enum Status {
  Active = 'active',
  Paused = 'paused',
  Off, // Error: you must specify a value for all members (or none of the members)
}

При желании можно использовать предложение of:

enum Status of string {
  Active,
  Paused,
  Off,
}

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

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

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

Числовое перечисление можно задать так:

enum Status {
  Active = 1,
  Paused = 2,
  Off = 3,
}

При желании можно использовать предложение of. Оно не влияет на проверку типов корректного перечисления Flow, а лишь гарантирует, что все элементы перечисления будут number в месте определения.

enum Status of number {
  Active = 1,
  Paused = 2,
  Off = 3,
}

Мы не разрешаем задавать значения числовых перечислений по умолчанию (в отличие от некоторых других языков), поскольку добавление или удаление элемента из середины такого перечисления изменит значения всех последующих элементов. Это может быть небезопасно (например, для push safety, сериализации и ведения журналов). Требование явно указывать перенумерацию заставляет пользователя задуматься о её последствиях.

Указанное значение должно быть числовым литералом. В JS отрицательные числа не являются литералами, но Flow также допускает отрицательные числовые инициализаторы.

Пример:

enum Status {
  Active = 1,
  Paused = 0,
  Off = -1,
}

Логические перечисления​

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

Логическое перечисление можно задать так:

enum Status {
  Active = true,
  Off = false,
}

При желании можно использовать предложение of. Оно не влияет на проверку типов корректного перечисления Flow, а лишь гарантирует, что все элементы перечисления будут boolean в месте определения.

enum Status of boolean {
  Active = true,
  Off = false,
}

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

Для перечислений BigInt необходимо указывать значения с помощью литералов bigint (например, 1n, 2n).

Перечисление bigint можно задать так:

enum Status {
  Active = 1n,
  Paused = 2n,
  Off = 3n,
}

При желании можно использовать предложение of. Оно не влияет на проверку типов корректного перечисления Flow, а лишь гарантирует, что все элементы перечисления будут bigint в месте определения.

enum Status of bigint {
  Active = 1n,
  Paused = 2n,
  Off = 3n,
}

Элементы перечислений BigInt можно использовать так же, как элементы других перечислений. Тип их представления — bigint:

enum Status of bigint {
  Active = 1n,
  Paused = 2n,
  Off = 3n,
}


const status: Status = Status.Active; // OK
status as bigint; // OK

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

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

Перечисление Symbol можно задать так:

enum Status of symbol {
  Active,
  Paused,
  Off,
}

Перечисления Flow с неизвестными элементами​

Указать, что перечисление содержит «неизвестные элементы», можно, добавив ... в конец объявления:

enum Status {
  Active,
  Paused,
  Off,
  ...
}
const status: Status = Status.Active;


switch (status) { // Error
  case Status.Active: break;
  case Status.Paused: break;
  case Status.Off: break;
}


match (status) { // Error
  Status.Active => {}
  Status.Paused => {}
  Status.Off => {}
}

При этом Flow всегда будет требовать default (для switch) или подстановочный знак _ (для match) при проверке перечисления, даже если проверены все известные элементы. Проверки default/_ выявляют «неизвестные» элементы, которые вы явно не перечислили.

Эта возможность полезна, когда значение перечисления пересекает некоторую границу, а объявления перечисления с каждой стороны могут содержать разные элементы. Например, определение перечисления может использоваться и на клиенте, и на сервере: в него можно добавить элемент, который сразу станет известен серверу, но может быть отправлен устаревшему клиенту, которому новый элемент ещё неизвестен.

Один из вариантов использования — JS-вывод перечислений GraphQL: вместо добавленного элемента '%future added value' можно использовать перечисления Flow с неизвестными элементами.

Перечисления во время выполнения​

Во время выполнения перечисления существуют как значения. Мы используем преобразование Babel, чтобы преобразовывать объявления перечислений Flow в вызовы среды выполнения перечислений (подробнее см. в разделе о включении перечислений). Среда выполнения позволяет всем перечислениям использовать общую реализацию методов перечислений.

Для прототипа перечислений (содержащего методы перечислений) используется Object.create(null), поэтому свойства в Object.prototype не засоряют перечисления. Собственные свойства объекта перечисления — только его элементы. Элементы не перечисляемы (для доступа к ним используйте метод .members()). Весь объект перечисления заморожен, поэтому его нельзя изменить.

Руководство по стилю​

Именование перечислений​

Рекомендуем задавать имена перечислений в PascalCase, следуя соглашениям об именовании других типов. Имена, состоящие только из заглавных букв (например, STATUS), сложнее читать, поэтому мы не рекомендуем их использовать.

Рекомендуем давать перечислениям имена в единственном числе. Например, Status, а не Statuses. Так же, как тип true и false — это boolean, а не booleans.

Не добавляйте Enum к имени (например, не называйте перечисление StatusEnum). В этом нет необходимости — точно так же, как мы не добавляем Class к имени каждого класса, а Type — к каждому псевдониму типа.

Именование элементов перечисления​

Рекомендуем задавать имена элементов перечисления в PascalCase. Имена, состоящие только из заглавных букв (например, ACTIVE), сложнее читать, поэтому мы не рекомендуем их использовать. Кроме того, Flow гарантирует, что эти значения являются константами, поэтому не нужно сигнализировать программисту об этом с помощью имени.

См. также правило о начальных символах имён элементов перечисления.

Не создавайте отдельный тип​

Перечисление Flow, как и класс, является одновременно типом и значением. Создавать отдельный псевдоним типа не нужно — можно использовать имя перечисления.

Используйте точечную запись для доступа к элементам​

Предпочитайте Status.Active вместо const {Active} = Status;. Так проще находить обращения к перечислению с помощью текстового поиска и понятнее, какое перечисление используется. Кроме того, это обязательно для операторов switch с перечислениями.

См. также​

  • Номинальная и структурная типизация — перечисления имеют номинальную типизацию, как и классы

© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/enums/defining-enums

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API