Skip to main content

使用枚举

Flow 枚举不是 联合类型 的语法。它们是自己的类型,并且 Flow Enum 的每个成员都具有相同的类型。大型联合类型可能会导致性能问题,因为 Flow 必须将每个成员视为单独的类型。使用 Flow Enums,无论你的枚举有多大,Flow 始终会表现出良好的性能,因为它只需要跟踪一种类型。

¥Flow Enums are not a syntax for union types. They are their own type, and each member of a Flow Enum has the same type. Large union types can cause performance issues, as Flow has to consider each member as a separate type. With Flow Enums, no matter how large your enum is, Flow will always exhibit good performance as it only has one type to keep track of.

我们在下面的示例中使用以下枚举:

¥We use the following enum in the examples below:

enum Status {
Active,
Paused,
Off,
}

访问枚举成员

¥Accessing enum members

使用点语法访问成员:

¥Access members with the dot syntax:

const status = Status.Active;

你不能使用计算访问:

¥You can’t use computed access:

1enum Status {2  Active,3  Paused,4  Off,5}6const x = "Active";7Status[x]; // Error: computed access on enums is not allowed

用作类型注释

¥Using as a type annotation

枚举声明定义了一个值(你可以从中访问枚举成员和方法)和一个同名的类型,该类型是枚举成员的类型。

¥The enum declaration defines both a value (from which you can access the enum members and methods) and a type of the same name, which is the type of the enum members.

function calculateStatus(): Status {
...
}

const status: Status = calculateStatus();

转换为表示类型

¥Casting to representation type

枚举不会隐式强制其表示类型,反之亦然。如果要从枚举类型转换为表示类型,可以使用显式强制转换 x as string

¥Enums do not implicitly coerce to their representation type or vice-versa. If you want to convert from the enum type to the representation type, you can use an explicit cast x as string:

1enum Status {Active, Paused, Off}2
3const s: string = Status.Active; // Error: 'Status' is not compatible with 'string'4
5declare const status: Status;6const statusString: string = status as string;

你还可以在枚举值上调用 .valueOf()

¥You can also call .valueOf() on the enum value

0.234

。如果你正在处理 抽象枚举 并且不知道表示类型,这尤其有用。

¥. This is particularly useful if you are dealing with abstract enums and don't know the representation type.

1enum Status {Active, Paused, Off}2
3declare const status: Status;4const statusString: string = status.valueOf();

要从可空枚举类型转换为可空表示类型,你可以执行以下操作:

¥To convert from a nullable enum type to nullable representation type, you can do:

1enum Status {Active, Paused, Off}2declare const maybeStatus: ?Status;3
4// Using `as` cast and `&&`:5const maybeStatusString1: ?string = maybeStatus && (maybeStatus as string);6
7// Using `.valueOf()` and optional chaining:8const maybeStatusString2: ?string = maybeStatus?.valueOf();

如果你想从表示类型(例如 string)转换为枚举类型(如果有效),请查看 铸造方法

¥If you want to convert from the representation type (e.g. string) to an enum type (if valid), check out the cast method.

方法

¥Methods

枚举声明还定义了一些有用的方法。

¥Enum declarations also define some helpful methods.

下面,TEnum 是枚举的类型(例如 Status),TRepresentationType 是该枚举的表示类型的类型(例如 string)。

¥Below, TEnum is the type of the enum (e.g. Status), and TRepresentationType is the type of the representation type for that enum (e.g. string).

.cast

类型:cast(input: ?TRepresentationType): TEnum | void

¥Type: cast(input: ?TRepresentationType): TEnum | void

cast 方法允许你安全地将原始值(如 string)转换为枚举类型(如果它是枚举的有效值),否则转换为 undefined

¥The cast method allows you to safely convert a primitive value, like a string, to the enum type (if it is a valid value of the enum), and undefined otherwise.

const data: string = getData();
const maybeStatus: Status | void = Status.cast(data);
if (maybeStatus != null) {
const status: Status = maybeStatus;
// do stuff with status
}

使用 ?? 运算符在一行中设置默认值:

¥Set a default value in one line with the ?? operator:

const status: Status = Status.cast(data) ?? Status.Off;

cast 的参数类型取决于枚举的类型。如果是 字符串枚举,则参数的类型将为 string。如果是 数字枚举,则参数的类型将为 number,依此类推。如果你希望转换 mixed 值,请首先使用 typeof 细化:

¥The type of the argument of cast depends on the type of enum. If it is a string enum, the type of the argument will be string. If it is a number enum, the type of the argument will be number, and so on. If you wish to cast a mixed value, first use a typeof refinement:

const data: mixed = ...;
if (typeof data === 'string') {
const maybeStatus: Status | void = Status.cast(data);
}

cast 使用 this(代表枚举成员的对象),所以如果你想将函数本身作为值传递,你应该使用箭头函数。例如:

¥cast uses this (representing the object of enum members), so if you want to pass the function itself as a value, you should use an arrow function. For example:

const strings: Array<string> = ...;
// WRONG: const statuses: Array<?Status> = strings.map(Status.cast);
const statuses: Array<?Status> = strings.map((input) => Status.cast(input)); // Correct

运行时成本:对于 镜像字符串枚举(例如 enum E {A, B}),由于成员名称与值相同,因此运行时成本是恒定的 - 相当于调用 .hasOwnProperty。对于其他枚举,第一次调用时会创建 Map,后续调用只需调用缓存映射上的 .has。因此成本是摊销不变的。

¥Runtime cost: For mirrored string enums (e.g enum E {A, B}), as the member names are the same as the values, the runtime cost is constant - equivalent to calling .hasOwnProperty. For other enums, a Map is created on the first call, and subsequent calls simply call .has on the cached map. Thus the cost is amoritzed constant.

.isValid

类型:isValid(input: ?TRepresentationType): boolean

¥Type: isValid(input: ?TRepresentationType): boolean

isValid 方法与 cast 类似,但仅返回一个布尔值:如果提供的输入是有效的枚举值,则为 true;如果不是,则为 false

¥The isValid method is like cast, but simply returns a boolean: true if the input supplied is a valid enum value, and false if it is not.

const data: string = getData();
const isStatus: boolean = Status.isValid(data);

isValid 使用 this(代表枚举成员的对象),所以如果你想将函数本身作为值传递,你应该使用箭头函数。例如:

¥isValid uses this (representing the object of enum members), so if you want to pass the function itself as a value, you should use an arrow function. For example:

const strings: Array<string> = ...;
// WRONG: const statusStrings = strings.filter(Status.isValid);
const statusStrings = strings.filter((input) => Status.isValid(input)); // Correct

运行时成本:与上面 .cast 中描述的相同。

¥Runtime cost: The same as described under .cast above.

.members

类型:members(): Iterator<TEnum>

¥Type: members(): Iterator<TEnum>

members 方法返回所有枚举成员的 迭代器 (可迭代)。

¥The members method returns an iterator (that is iterable) of all the enum members.

const buttons = [];
function getButtonForStatus(status: Status) { ... }

for (const status of Status.members()) {
buttons.push(getButtonForStatus(status));
}

迭代顺序保证与声明中成员的顺序相同。

¥The iteration order is guaranteed to be the same as the order of the members in the declaration.

枚举本身不可枚举或可迭代(例如,枚举上的 for-in/for-of 循环不会迭代其成员),你必须使用 .members() 方法来实现此目的。

¥The enum is not enumerable or iterable itself (e.g. a for-in/for-of loop over the enum will not iterate over its members), you have to use the .members() method for that purpose.

你可以使用以下方法将 iterable 转换为 ArrayArray.from(Status.members())。你可以在构造数组的同时使用 Array.from 的第二个参数来映射值:例如

¥You can convert the iterable into an Array using: Array.from(Status.members()). You can make use of Array.from's second argument to map over the values at the same time you construct the array: e.g.

const buttonArray = Array.from(
Status.members(),
status => getButtonForStatus(status),
);

.getName

类型:getName(value: TEnum): string

¥Type: getName(value: TEnum): string

getName 方法将枚举值映射到该值的枚举成员的字符串名称。使用 number/boolean/symbol 枚举时,这对于调试和生成内部 CRUD UI 很有用。例如:

¥The getName method maps enum values to the string name of that value's enum member. When using number/boolean/symbol enums, this can be useful for debugging and for generating internal CRUD UIs. For example:

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

console.log(Status.getName(status));
// Will print a string, either "Active", "Paused", or "Off" depending on the value.

运行时成本:与上面 .cast 中描述的相同。从枚举值到枚举名称的单个缓存反向映射用于 .cast.isValid.getName。第一次调用任何这些方法都将创建此缓存的映射。

¥Runtime cost: The same as described under .cast above. A single cached reverse map from enum value to enum name is used for .cast, .isValid, and .getName. The first call of any of those methods will create this cached map.

使用 switch 彻底检查枚举

¥Exhaustively checking enums with a switch

在检查 switch 语句中的枚举值时,我们强制你检查所有可能的枚举成员,并且不包括多余的情况。这有助于确保你在编写使用枚举的代码时考虑所有可能性。它特别有助于在添加或删除成员时进行重构,指出需要更新的不同位置。

¥When checking an enum value in a switch statement, we enforce that you check against all possible enum members, and don’t include redundant cases. This helps ensure you consider all possibilities when writing code that uses enums. It especially helps with refactoring when adding or removing members, by pointing out the different places you need to update.

const status: Status = ...;

switch (status) { // Good, all members checked
case Status.Active:
break;
case Status.Paused:
break;
case Status.Off:
break;
}

你可以使用 default 来匹配到目前为止尚未检查的所有成员:

¥You can use default to match all members not checked so far:

switch (status) {
case Status.Active:
break;
default: // When `Status.Paused` or `Status.Off`
break;
}

你可以在一个 switch case 中检查多个枚举成员:

¥You can check multiple enum members in one switch case:

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

你必须匹配枚举的所有成员(或提供 default 情况):

¥You must match against all of the members of the enum (or supply a default case):

1enum Status {2  Active = 1,3  Paused = 2,4  Off = 3,5}6const status: Status = Status.Active;7
8// Error: you haven't checked 'Status.Off' in the switch9switch (status) {10  case Status.Active:11    break;12  case Status.Paused:13    break;14}

你不能重复案例(因为这将是死代码!):

¥You can’t repeat cases (as this would be dead code!):

1enum Status {2  Active = 1,3  Paused = 2,4  Off = 3,5}6const status: Status = Status.Active;7
8switch (status) {9  case Status.Active:10    break;11  case Status.Paused:12    break;13  case Status.Off:14    break;15  case Status.Paused: // Error: you already checked for 'Status.Paused'16    break;17}

如果你已经匹配了所有案例,则 default 案例是多余的:

¥A default case is redundant if you’ve already matched all cases:

1enum Status {2  Active = 1,3  Paused = 2,4  Off = 3,5}6const status: Status = Status.Active;7
8switch (status) {9  case Status.Active:10    break;11  case Status.Paused:12    break;13  case Status.Off:14    break;15  default: // Error: you've already checked all cases, the 'default' is redundant16    break;17}18// The following is OK because the `default` covers the `Status.Off` case:19switch (status) {20  case Status.Active:21    break;22  case Status.Paused:23    break;24  default:25    break;26}

除非你使用 未知成员 切换枚举。

¥Except if you are switching over an enum with unknown members.

如果你将详尽检查的开关嵌套在详尽检查的开关内,并且从每个分支返回,则必须在嵌套开关后添加 break;

¥If you nest exhaustively checked switches inside exhaustively checked switches, and are returning from each branch, you must add a break; after the nested switch:

switch (status) {
case Status.Active:
return 1;
case Status.Paused:
return 2;
case Status.Off:
switch (otherStatus) {
case Status.Active:
return 1;
case Status.Paused:
return 2;
case Status.Off:
return 3;
}
break;
}

请记住,你可以向开关盒添加块。如果你想使用局部变量,它们很有用:

¥Remember, you can add blocks to your switch cases. They are useful if you want to use local variables:

switch (status) {
case Status.Active: {
const x = f();
...
break;
}
case Status.Paused: {
const x = g();
...
break;
}
case Status.Off: {
const y = ...;
...
break;
}
}

如果在此示例中未添加块,则 const x 的两个声明将发生冲突并导致错误。

¥If you didn't add blocks in this example, the two declarations of const x would conflict and result in an error.

if 语句或 switch 语句以外的其他上下文中,不会对枚举进行详尽检查。

¥Enums are not checked exhaustively in if statements or other contexts other than switch statements.

对未知成员进行详尽检查

¥Exhaustive checking with unknown members

如果你的枚举有 未知成员(用 ... 指定),例如

¥If your enum has unknown members (specified with the ...), e.g.

enum Status {
Active,
Paused,
Off,
...
}

那么切换枚举时总是需要 defaultdefault 检查你未明确列出的 "未知" 成员。

¥Then a default is always required when switching over the enum. The default checks for "unknown" members you haven't explicitly listed.

switch (status) {
case Status.Active:
break;
case Status.Paused:
break;
case Status.Off:
break;
default:
// Checks for members not explicitly listed
}

你可以使用 require-explicit-enum-switch-cases Flow Lint 要求将所有已知成员明确列为案例。例如:

¥You can use the require-explicit-enum-switch-cases Flow Lint to require that all known members are explicitly listed as cases. For example:

1enum Status {2  Active = 1,3  Paused = 2,4  Off = 3,5}6const status: Status = Status.Active;7
8// flowlint-next-line require-explicit-enum-switch-cases:error9switch (status) {10  case Status.Active:11    break;12  case Status.Paused:13    break;14  default:15    break;16}

你可以通过执行以下操作来修复:

¥You can fix if by doing:

// flowlint-next-line require-explicit-enum-switch-cases:error
switch (status) {
case Status.Active:
break;
case Status.Paused:
break;
case Status.Off: // Added the missing `Status.Off` case
break;
default:
break;
}

require-explicit-enum-switch-cases lint 不是全局启用的,而是在你需要该行为时在每个 switch 基础上启用。对于普通枚举,对于其上的每个 switch 语句,你可以提供或不提供 default,从而决定是否需要显式列出每种情况。同样,对于具有未知成员的 Flow 枚举,你也可以在每个交换机上启用此 lint。

¥The require-explicit-enum-switch-cases lint is not one to enable globally, but rather on a per-switch basis when you want the behavior. With normal enums, for each switch statement on it, you can either provide a default or not, and thus decide if you want to require each case explicitly listed or not. Similarly for Flow Enums with unknown members, you can also enable this lint on a per-switch basis.

lint 也适用于常规 Flow Enum 类型的开关。它实际上禁止在 switch 语句中使用 default,要求明确列出所有枚举成员作为案例。

¥The lint works for switches of regular Flow Enum types as well. It in effect bans the usage of default in that switch statement, by requiring the explicit listing of all enum members as cases.

将枚举映射到其他值

¥Mapping enums to other values

你可能希望将枚举值映射到另一个值的原因有多种,例如 标签、图标、元素等。

¥There are a variety of reasons you may want to map an enum value to another value, e.g. a label, icon, element, and so on.

在以前的模式中,通常使用对象字面量来实现此目的,但是对于 Flow 枚举,我们更喜欢包含开关的函数,我们可以详尽地检查它。

¥With previous patterns, it was common to use object literals for this purpose, however with Flow Enums we prefer functions which contain a switch, which we can exhaustively check.

代替:

¥Instead of:

const STATUS_ICON: {[Status]: string} = {
[Status.Active]: 'green-checkmark',
[Status.Paused]: 'grey-pause',
[Status.Off]: 'red-x',
};
const icon = STATUS_ICON[status];

这实际上并不能保证我们将每个 Status 映射到某个值,请使用:

¥Which doesn't actually guarantee that we are mapping each Status to some value, use:

function getStatusIcon(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 = getStatusIcon(status);

将来,如果你添加或删除枚举成员,Flow 也会告诉你更新开关,以便它始终准确。

¥In the future if you add or remove an enum member, Flow will tell you to update the switch as well so it's always accurate.

如果你确实想要一本不详尽的字典,你可以使用 Map

¥If you actually want a dictionary which is not exhaustive, you can use a Map:

const counts = new Map<Status, number>([
[Status.Active, 2],
[Status.Off, 5],
]);
const activeCount: Status | void = counts.get(Status.Active);

Flow 枚举不能用作对象字面量中的键,如 本页稍后解释

¥Flow Enums cannot be used as keys in object literals, as explained later on this page.

联合中的枚举

¥Enums in a union

如果你的枚举值位于联合中(例如 ?Status),请首先细化为仅枚举类型:

¥If your enum value is in a union (e.g. ?Status), first refine to only the enum type:

const status: ?Status = ...;

if (status != null) {
status as Status; // 'status' is refined to 'Status' at this point
switch (status) {
case Status.Active: break;
case Status.Paused: break;
case Status.Off: break;
}
}

如果要细化为枚举值,可以将 typeof 与表示类型一起使用,例如:

¥If you want to refine to the enum value, you can use typeof with the representation type, for example:

const val: Status | number = ...;

// 'Status' is a string enum
if (typeof val === 'string') {
val as Status; // 'val' is refined to 'Status' at this point
switch (val) {
case Status.Active: break;
case Status.Paused: break;
case Status.Off: break;
}
}

导出枚举

¥Exporting enums

枚举是一种类型和一个值(就像类一样)。要导出类型和值,请像导出值一样导出它:

¥An enum is a type and a value (like a class is). To export both the type and the value, export it like a you would a value:

1export enum Status {}

或者,作为默认导出(注意:你必须始终指定枚举名称,不允许使用 export default enum {}):

¥Or, as the default export (note: you must always specify an enum name, export default enum {} is not allowed):

1export default enum Status {}

使用 CommonJS:

¥Using CommonJS:

1enum Status {}2module.exports = Status;

要仅导出其类型而不导出值,你可以执行以下操作:

¥To export only its type, but not the value, you can do:

1enum Status {}2export type {Status};

文件中的其他函数仍然可以访问枚举实现。

¥Other functions within the file will still have access to the enum implementation.

导入枚举

¥Importing enums

如果你导出了这样的枚举:

¥If you have exported an enum like this:

1// status.js2export default enum Status {3  Active,4  Paused,5  Off,6}

你可以将其作为值和类型导入,如下所示:

¥You can import it as both a value and a type like this:

import Status from 'status';

const x: Status /* used as type */ = Status.Active /* used as value */;

如果只需要使用类型,可以将其作为类型导入:

¥If you only need to use the type, you can import it as a type:

import type Status from 'status';

function printStatus(status: Status) {
...
}

使用 CommonJS:

¥Using CommonJS:

const Status = require('status');

抽象枚举

¥Abstract enums

0.234

{#toc-abstract-enums}

你可以使用两种类型以通用方式编写对 Flow Enum 进行操作的代码:Enum<>EnumValue<>,它们接受任何 Flow Enum 及其值。

¥You can write code that operates on Flow Enums in a generic way using two types: Enum<> and EnumValue<>, which accept any Flow Enum and its values.

枚举值<>

¥EnumValue<>

EnumValue<> 接受任何 Flow Enum 值。想要将其缩小到具有特定表示类型的枚举值吗?只需添加一个类型参数:

¥EnumValue<> accepts any Flow Enum value. Want to narrow it down to enum values with a specific representation type? Just add a type argument:

1enum Status {Active, Paused, Off}2
3Status.Active as EnumValue<>; // OK4Status.Active as EnumValue<string>; // OK - its a string enum5Status.Active as EnumValue<number>; // ERROR - not a number enum

新的 EnumRepresentationTypes 类型代表所有有效的表示类型:stringnumber

¥The new EnumRepresentationTypes type represents all the valid representation types: string, number, etc.

Flow Enum 值不会隐式强制转换为其表示类型,因此我们允许 显式转换 使用像 Status.Active as string 这样的强制转换。使用 EnumValue<> 时,你可能不知属性体的表示类型,因此我们现在允许直接在枚举值上使用 .valueOf() 进行强制转换。例如:

¥Flow Enum values don’t implicitly coerce to their representation type, so we allow explicit conversion with casts like Status.Active as string. With EnumValue<> you might not know the specific representation type, so we now allow casts using .valueOf() directly on the enum value. For example:

1function f(e: EnumValue<>) {2  const x: EnumRepresentationTypes = e.valueOf(); // OK3}

枚举<>

¥Enum<>

Enum<> 接受任何 Flow Enum - 枚举本身,而不是它的值。你可以选择提供一个类型参数来将其限制为具有特定枚举值的枚举,你可以将其与上面的 EnumValue 类型配对:

¥Enum<> accepts any Flow Enum - the enum itself, rather than its value. You can optionally supply a type argument to restrict it to enums with a certain enum value, which you can pair with the EnumValue type above:

1enum Status {Active, Paused, Off}2
3Status as Enum<>; // OK4Status as Enum<Status>; // OK5Status as Enum<EnumValue<string>>; // OK

使用 Enum<> 类型,你可以使用所有 Flow Enum 方法,如 .cast.members。这让你可以编写通用处理 Flow Enums 的代码,例如仅从 Flow Enum 创建完整的 React 选择器组件:

¥With the Enum<> type you can use all the Flow Enum methods like .cast and .members. This lets you craft code that generically handles Flow Enums, for example creating a full React selector component from only a Flow Enum:

用法

¥Usage

enum Status {
Active,
Paused,
Off,
}
<Selector items={Status} callback={doStuff} />
定义

¥Definition

1import * as React from 'react';2import {useCallback, useMemo, useState} from 'react';3
4component Selector<5  TEnumValue: EnumValue<string>,6>(7  items: Enum<TEnumValue>,8  callback: (TEnumValue) => void,9) {10  // Typing the `useState` selector with the enum value generic11  const [value, setValue] = useState<?TEnumValue>(null);12
13  const handleChange = useCallback((e: SyntheticInputEvent<>) => {14    // Using the `.cast` method15    const value = items.cast(e.target.value);16    if (value == null) { throw new Error("Invalid value"); }17    setValue(value);18    callback(value);19  }, [items, callback]);20
21  return <ul>22    {Array.from(items.members(), item => // Using the `.members()` method23      <li>24        <label>25          {// Using the `.getName` method:26            items.getName(item)27          }:28          <input29            type="radio"30            // Casting to the representation type using `.valueOf()`31            value={item.valueOf()}32            checked={item === value}33            onChange={handleChange} />34         </label>35      </li>36    )}37  </ul>;38}

何时不使用枚举

¥When to not use 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 these cases, you can continue to use existing patterns to satisfy your use cases.

不同的对象键

¥Distinct object keys

你不能使用枚举成员作为不同的对象键。

¥You can’t use enum members as distinct object keys.

由于 LegacyStatus.ActiveLegacyStatus.Off 的类型不同,因此以下模式有效。一种为 'Active' 型,一种为 'Off' 型。

¥The following pattern works because the types of LegacyStatus.Active and LegacyStatus.Off are different. One has the type 'Active' and one has the type 'Off'.

1const LegacyStatus = Object.freeze({2  Active: 'Active',3  Paused: 'Paused',4  Off: 'Off',5});6const o = {7  [LegacyStatus.Active]: "hi",8  [LegacyStatus.Off]: 1,9};10const x: string = o[LegacyStatus.Active]; // OK11const y: number = o[LegacyStatus.Off]; // OK12const z: boolean = o[LegacyStatus.Active]; // Error - as expected

我们不能对枚举使用相同的模式。所有枚举成员都具有相同的类型,即枚举类型,因此 Flow 无法跟踪键和值之间的关系。

¥We can’t use the same pattern with enums. All enum members have the same type, the enum type, so Flow can’t track the relationship between keys and values.

如果你希望从一个枚举值映射到另一个值,你应该使用 功能与一个彻底检查的开关代替

¥If you wish to map from an enum value to another value, you should use a function with an exhaustively-checked switch instead.

不相交对象联合

¥Disjoint object unions

枚举的一个定义特性是,与联合不同,每个枚举成员不形成自己的单独类型。每个成员都有相同的类型,即枚举类型。这允许 Flow 以一致的快速方式分析枚举的使用情况,但这意味着在某些需要单独类型的情况下,我们不能使用枚举。考虑以下联合,遵循 不相交的对象并集 模式:

¥A defining feature of enums is that unlike unions, each enum member does not form its own separate type. Every member has the same type, the enum type. This allows enum usage to be analyzed by Flow in a consistently fast way, however it means that in certain situations which require separate types, we can’t use enums. Consider the following union, following the disjoint object union pattern:

1type Action =2  | {type: 'Upload', data: string}3  | {type: 'Delete', id: number};

联合中的每个对象类型都有一个公共字段 (type),用于区分我们正在处理的对象类型。

¥Each object type in the union has a single common field (type) which is used to distinguish which object type we are dealing with.

我们不能对该字段使用枚举类型,因为要使该机制发挥作用,该字段的类型在联合体的每个成员中必须不同,但枚举成员都具有相同的类型。

¥We can’t use enum types for this field, because for this mechanism to work, the type of that field must be different in each member of the union, but enum members all have the same type.

将来,我们可能会添加枚举的功能,以封装除键和原始值之外的其他数据 - 这将使我们能够替换不相交的对象联合。

¥In the future, we might add the ability for enums to encapsulate additional data besides a key and a primitive value - this would allow us to replace disjoint object unions.

保证内联

¥Guaranteed inlining

Flow Enums 被设计为允许内联(例如 成员值必须是字面量枚举被冻结),但是内联本身需要成为构建系统(无论你使用什么)的一部分,而不是 Flow 本身。

¥Flow Enums are designed to allow for inlining (e.g. member values must be literals, enums are frozen), however the inlining itself needs to be part of the build system (whatever you use) rather than Flow itself.

虽然枚举成员访问(例如 Status.Active)可以内联(符号枚举 除外,由于符号的性质而无法内联),但其方法的使用(例如 Status.cast(x))无法内联。

¥While enum member access (e.g. Status.Active) can be inlined (other than symbol enums which cannot be inlined due to the nature of symbols), usage of its methods (e.g. Status.cast(x)) cannot be inlined.