Defining enums
Learn how to define a Flow Enum. Looking for a quick overview? Check out the Quickstart Guide.
An enum declaration is a statement. Its name defines both a value (from which to access its members, and call its methods), and a type (which can be used as an annotation for the type of its members).
Enum members must all be of the same type, and those members can be one of four types: string, number, boolean, and symbol.
Every enum has some common properties:
Consistent member type
The type of the enum members must be consistent. For example, you can’t mix string
and number
members in one enum. They must all be strings, numbers, or booleans (you do not provide values for symbol
based enums).
Member name starting character
Member names must be valid identifiers (e.g. not start with numbers), and must not start with lowercase a
through z
. Names starting with those letters are reserved for enum methods (e.g. Status.cast(...)
).
This is not allowed:
// @flow enum Status { active, // Error: names can't start with lowercase 'a' through 'z' }
Unique member names
Member names must be unique. This is not allowed:
// @flow enum Status { Active, Active, // Error: the name 'Active` was already used above }
Literal member values
If you specify a value for an enum member, it must be a literal (string, number, or boolean), not a computed value. This is not allowed:
// @flow enum Status { Active = 1 + 2, // Error: the value must be a literal }
Unique member values
Member values must be unique. This is not allowed:
enum Status { Active = 1, Paused = 1, // Error: the value has already been used above }
Fixed at declaration
An enum is not extendable, so you can’t add new members after the fact while your code is running. At runtime, enum member values can’t change and the members can’t be deleted. In this way they act like a frozen object.
String enums
String enums are the default. If you don’t specify an of
clause (e.g. enum Status of number {}
, enum Status of symbol {}
, etc.), and do not specify any values (e.g. enum Status {Active = 1}
) then the definition will default to be a string enum.
Unlike the other types of enums (e.g. number enums), you can either specify values for the enum members, or not specify values and allow them to be defaulted.
If you don’t specify values for your enum members, they default to strings which are the same as the name of your members.
enum Status { Active, Paused, Off, }
Is the same as:
enum Status { Active = 'Active', Paused = 'Paused', Off = 'Off', }
You must consistently either specify the value for all members, or none of the members. This is not allowed:
// @flow enum Status { Active = 'active', Paused = 'paused', Off, // Error: you must specify a value for all members (or none of the members) }
Optionally, you can use an of
clause:
enum Status of string { Active, Paused, Off, }
We infer the type of the enum based on its values if there is no of
clause. Using an of
clause will ensure that if you use incorrect values, the error message will always interpret it as an enum of that type.
Number enums
Number enums must have their values specified.
You can specify a number enum like this:
enum Status { Active = 1, Paused = 2, Off = 3, }
Optionally, you can use an of
clause:
enum Status of number { Active = 1, Paused = 2, Off = 3, }
We do not allow defaulting of number enums (unlike some other languages), because if a member from the middle of such an enum is added or removed, all subsequent member values would be changed. This can be unsafe (e.g. push safety, serialization, logging). Requiring the user to be explicit about the renumbering makes them think about the consequences of doing so.
The value provided must be a number literal. (Note: there is no literal for negative numbers in JavaScript, they are the application of a unary -
operation on a number literal.) We could expand allowed values in the future to include certain non-literals, if requests to do so arise.
Boolean enums
Boolean enums must have their values specified. Boolean enums can only have two members.
You can specify a boolean enum like this:
enum Status { Active = true, Off = false, }
Optionally, you can use an of
clause:
enum Status of boolean { Active = true, Off = false, }
Symbol enums
Symbol enums can’t have their values specified. Each member is a new symbol, with the symbol description set to the name of the member. You must use the of
clause with symbol enums, to distinguish them from string enums, which are the default when omitting values.
You can specify a symbol enum like this:
enum Status of symbol { Active, Paused, Off, }
Flow Enums with Unknown Members
You can specify that your enum contains “unknown members” by adding a ...
to the end of the declaration:
enum Status { Active, Paused, Off, ... }
When this is used, Flow will always require a default
when switching over the enum, even if all known enum members are checked. The default
checks for “unknown” members you haven’t explicitly listed.
This feature is useful when an enum value crosses some boundary and the enum declaration on each side may have different memebers. For example, an enum definition which is used on both the client and the server: an enum member could be added, which would be immediately seen by the server, but could be sent to an outdated client which isn’t yet aware of the new member.
One use case for this would be the JS output of GraphQL Enums: Flow Enums with unknown members could be used instead of the added '%future added value'
member.
Enums at runtime
Enums exist as values at runtime. We use a Babel transform to transform Flow Enum declarations into calls to the enums runtime (read more in the enabling enums documentation). We use a runtime so all enums can share an implementation of the enum methods.
We use Object.create(null)
for enums’ prototype (which has the enum methods), so properties in Object.prototype
will not pollute enums. The only own properties of the enum object are the enum members. The members are non-enumerable (use the .members()
method for that). The entire enum object is frozen, so it cannot be modified.
Style guide
Naming enums
We encourage you to define enum names in PascalCase
, following the naming conventions of other types. All caps names (e.g. STATUS
) are harder to read and discouraged.
We encourage you to name enums in the singular. E.g. Status
, not Statuses
. Just like the type of true
and false
is boolean
, not booleans
.
Don’t append Enum
to the name (e.g. don’t name your enum StatusEnum
). This is unnecessary, just like we don’t append Class
to every class name, and Type
to every type alias.
Naming enum members
We encourage you to define enum member names in PascalCase
. All caps names (e.g. ACTIVE
) are harder to read and discouraged. Additionally, since Flow enforces that these are constants, you don’t need to use the name to signal that intent to the programmer.
See also: the rule about enum member name starting characters.
Don’t create a separate type
A Flow Enum, like a class, is both a type and a value. You don’t need to create a separate type alias, you can use the enum name.
Use dot access for accessing members
Prefer Status.Active
vs. const {Active} = Status; Active
. This makes it easier find uses of the enum with text search, and makes it clearer to the reader what enum is involved. Additionally, this is required for switch statements involving enums.
© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/enums/defining-enums