Migrating from legacy patterns
Learn how to migrate to Flow Enums from legacy JavaScript enum patterns like Object.freeze
.
First, learn how to update the enum definition site, and next learn how to update files that import and use the enum.
Updating definitions
Object.freeze
If you are using Object.freeze
, you can migrate to an enum if the values of the object are:
- All the same primitive type, and that type is
boolean
,string
,number
, orsymbol
. - All literals.
- Contain no duplicate values.
Replace
const Status = Object.freeze({ Active: 1, Paused: 2, Off: 3, }); export type StatusType = $Values<typeof Status>; export default Status;
with
export default enum Status { Active = 1, Paused = 2, Off = 3, }
- Check to ensure that the key names do not start with lowercase ‘a’-‘z’ (disallowed in enums). If they do, you’ll need to rename the member names.
- Remove any usage of
$Keys<...>
or$Values<...>
on the enum type, these are no longer needed as a Flow Enum defines a type itself (its name). - Delete any type exports based on the enum, as you just need to export the Flow Enum. A Flow Enum acts as both a type and a value (like a class).
Then, take a look at how to update files that import and use the enum.
keyMirror
The keyMirror
utility creates an object whose values are mirrors of its key names. You can replace keyMirror
usage with a string based enum.
Replace
import keyMirror from 'keyMirror'; const Status = keyMirror({ Active: null, Paused: null, Off: null, }); export type StatusType = $Keys<typeof Status>; export default Status;
with
export default enum Status { Active, Paused, Off, }
- Check to ensure that the key names do not start with lowercase ‘a’-‘z’ (disallowed in enums). If they do, you’ll need to rename the member names.
- Remove any usage of
$Keys<...>
on the enum type, it’s no longer needed as a Flow Enum defines a type itself (its name). - Delete any type exports based on the enum, you just need to export the Flow Enum. A Flow Enum acts as both a type and a value (like a class).
Then, take a look at how to update files that import and use the enum.
Updating usage
Fix type imports
Previous patterns required you to export (and then import) a type separate from the enum itself. Flow Enums are both types and values (like a class), so you just need to export the Flow Enum itself. Since there is now one export, you only need one import. Read more about exporting enums and importing enums.
If you previously had:
const Status = Object.freeze({ Active: 1, Paused: 2, Off: 3, }); export type StatusType = $Values<typeof Status>; export default Status;
And you’ve replaced it with:
export default enum Status { Active = 1, Paused = 2, Off = 3, }
Then you need to fix the imports as well:
If both type and value were imported
For a user of the enum, if you previously imported both the type and the value, you can delete the type import and update annotations used.
Change
import type {StatusType} from 'status'; import Status from 'status'; const myStatus: StatusType = Status.Active;
to
// Type import is deleted import Status from 'status'; const myStatus: Status = Status.Active; // Changed type annotation to just `Status`
If only the type was imported
For a user of the enum, if you previously imported just the type, change the type import to a default import rather than a named import.
Change
import type {StatusType} from 'status'; function isActive(status: StatusType) { ... }
to
// Remove the braces `{` `}` and changed the name - this is a default import now import type Status from 'status'; function isActive(status: Status) { ... } // Changed type annotation to just `Status`
Mapping enums to other values
Sometimes you want to map from an enum value to some other value. Previously, we sometimes used object literals for this. With Flow Enums, use a function with a switch
instead. The switch is exhaustively checked, so Flow will ensure you update your mapping when you add or remove Flow Enum members.
Replace this pattern
const STATUS_ICON: {[Status]: string} = { [Status.Active]: 'green-checkmark', [Status.Paused]: 'grey-pause', [Status.Off]: 'red-x', }; const icon = STATUS_ICON[status];
with
function statusIcon(status: Status): string { switch (status) { case Status.Active: return 'green-checkmark'; case Status.Paused: return 'grey-pause'; case Status.Off: return 'red-x'; } } const icon = statusIcon(status);
Read more about mapping enums to other values.
Usage as the representation type (e.g. a string)
You can’t use a Flow Enum directly as its representation type (e.g. a string
). If you get Flow errors about using an enum as its representation type, first try to refactor your code so that it expects the enum type instead of the representation type (e.g. change annotations from string
to Status
). If you really want to use the enum as its representation type, you can add in explicit casts. See casting to represetation type.
Casting to the enum type
If before you cast from an enum’s representation type (e.g. string
) to the enum type with something like this:
function castToStatus(input: number): StatusType | void { switch(input) { case 1: return Status.Active; case 2: return Status.Paused; case 3: return Status.Off; default: return undefined; } } castToStatus(x);
You can now just use the cast method:
Status.cast(x);
Update switch statements
Flow Enums are exhaustively checked in switch
statements. You might need to update your code when you are switching over an enum value. Read more at exhaustively checking enums in switch statements.
Operations over enum members
If previously you used functionality like Object.values
, Object.keys
, or for-in
loops to get and operate on the enum members, you can use the members method instead.
© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/enums/migrating-legacy-patterns