Flow Enums
Flow Enums define a fixed set of constants which create their own type.
Unlike other features of Flow, Flow Enums exist as values at runtime, as well as existing as types.
Read how to enable Flow Enums in your project.
Benefits
Enums provide several benefits over existing patterns:
- Reduce repetition: Enum declarations provide both the type and the value of the enum.
- Improve Flow performance: Enums are guaranteed to have good type-checking performance, unlike unions which may be expensive to type-check in certain situations.
- Enable new functionality: Enums come with a
cast
method, which converts from a primitive type to an enum type safely. - Enhance safety: Enums define their own type which does not implicitly coerce to and from other types (e.g. from
string
s), and are required to be exhaustively checked in switch statements. These properties can help prevent logic bugs.
Quickstart
Defining enums
An enum named Status
with three members: Active
, Paused
, and Off
.
1enum Status {2 Active,3 Paused,4 Off,5}
By default, enums define members with string values which mirror their names. You can also explicitly set values:
1enum Status {2 Active = 'active',3 Paused = 'paused',4 Off = 'off',5}
You can use numbers as well:
1enum Status {2 Active = 1,3 Paused = 2,4 Off = 3,5}
Values must be unique, literals, and all of the same type. Check out the full docs on defining enums to learn more.
Using enums
To access an enum member, use dot access:
Status.Active
To use the enum type as an annotation, use the enum name:
const status: Status = Status.Active;
Cast from the representation type (in this case, a string
) to the enum type:
const status: Status | void = Status.cast(someString);
You can easily provide a default value with the ??
operator:
const status: Status = Status.cast(someString) ?? Status.Off;
Read more about the other methods enums provide, including isValid
, members
, and getName
.
Cast an enum type to its representation type (must be done explicitly):
status as string
Checks of enums in switch
statements are exhaustive - we ensure you check all members:
1enum Status {2 Active,3 Paused,4 Off,5}6const status: Status = Status.Active;7
8// ERROR: Incomplete exhaustive check9switch (status) { 10 case Status.Active: break;11 case Status.Paused: break;12 // We forgot to add `case: Status.Off:` here, resulting in error above.13 // Using `default:` would also work to check all remaining members.14}
9:9-9:14: Incomplete exhaustive check: the member `Off` of enum `Status` [1] has not been considered in check of `status`. [invalid-exhaustive-check]
Read more about exhaustively checking enums.
Check out the the full docs on using enums to learn more.
When to use Flow Enums
If you previously defined a union type of literals, you can use an enum to define that type instead. Instead of
1type Status =2 | 'Active'3 | 'Paused'4 | 'Off';5
6const x: Status = 'Active';
or
1const Status = Object.freeze({2 Active: 'Active',3 Paused: 'Paused',4 Off: 'Off',5});6type StatusType = $Keys<typeof Status>;7const x: StatusType = Status.Active;
you can use:
1enum Status {2 Active,3 Paused,4 Off,5}6const x: Status = Status.Active;
See migrating from legacy patterns to learn more about migrating legacy JavaScript enum patterns to Flow Enums.
When to not use Flow Enums
Enums are designed to cover many use cases and exhibit certain benefits. The design makes a variety of trade-offs to make this happen, and in certain situations, these trade-offs might not be right for you. In those cases, you can continue to use existing patterns to satisfy your use cases. Read more about those situations.