跳至主要内容

定义枚举

了解如何定义 Flow 枚举。想要快速概览?请查看 快速入门指南.

枚举声明是一个语句。它的名称定义了一个值(从中 访问其成员,并调用其 方法)和一个类型(可以 用作其成员类型的注解)。

枚举成员必须都是相同类型,这些成员可以是以下四种类型之一:字符串数字布尔值符号

每个枚举都有一些共同的属性

一致的成员类型

枚举成员的类型必须一致。例如,您不能在一个枚举中混合使用 stringnumber 成员。它们必须都是字符串、数字或布尔值(您不需要为基于 symbol 的枚举提供值)。

成员名称起始字符

成员名称必须是有效的标识符(例如,不能以数字开头),并且不能以小写字母 az 开头。以这些字母开头的名称保留用于枚举 方法(例如,Status.cast(...))。

以下情况不允许

1enum Status {2  active, // Error: names can't start with lowercase 'a' through 'z'
3}
2:3-2:8: Enum member names cannot start with lowercase 'a' through 'z'. Instead of using `active`, consider using `Active`, in enum `Status`.

唯一的成员名称

成员名称必须是唯一的。以下情况不允许

1enum Status {2  Active,3  Active, // Error: the name 'Active` was already used above
4}
3:3-3:8: Enum member names need to be unique, but the name `Active` has already been used before in enum `Status`.

文字成员值

如果您为枚举成员指定一个值,它必须是一个文字(字符串、数字或布尔值),而不是一个计算值。以下情况不允许

1enum Status {2  Active = 1 + 2, // Error: the value must be a literal
3}
2:12-2:12: The enum member initializer for `Active` needs to be a literal (either a boolean, number, or string) in enum `Status`.

唯一的成员值

成员值必须是唯一的。以下情况不允许

1enum Status {2  Active = 1,3  Paused = 1, // Error: the value has already been used above
4}
3:12-3:12: Invalid enum member initializer. Initializers need to be unique, but this one has already been used for a previous member [1] of enum `Status` [2]. [duplicate-enum-init]

在声明时固定

枚举不可扩展,因此您不能在代码运行时添加新的成员。在运行时,枚举成员值不能更改,并且成员不能删除。这样一来,它们的行为就像一个冻结的对象。

字符串枚举

字符串枚举是默认的。如果您没有指定 of 子句(例如,enum Status of number {}enum Status of symbol {} 等),并且没有指定任何值(例如,enum Status {Active = 1}),那么定义将默认为字符串枚举。

与其他类型的枚举(例如,数字枚举)不同,您可以为枚举成员指定值,也可以不指定值并让它们默认。

如果您没有为枚举成员指定值,它们将默认设置为与成员名称相同的字符串。

1enum Status {2  Active,3  Paused,4  Off,5}

与以下情况相同

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

您必须始终为所有成员指定值,或者不为任何成员指定值。以下情况不允许

1enum Status {2  Active = 'active',3  Paused = 'paused',4  Off, // Error: you must specify a value for all members (or none of the members)
5}
4:3-4:5: String enum members need to consistently either all use initializers, or use no initializers, in enum Status.

您可以选择使用 of 子句

1enum Status of string {2  Active,3  Paused,4  Off,5}

如果不存在 of 子句,我们将根据枚举的值推断枚举的类型。使用 of 子句将确保,如果您使用不正确的值,错误消息将始终将其解释为该类型的枚举。

数字枚举

数字枚举必须指定其值。

您可以像这样指定数字枚举

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

您可以选择使用 of 子句。这不会影响有效 Flow 枚举的类型检查行为,它只是确保所有枚举成员在定义位置都是 number

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

我们不允许数字枚举默认(与其他一些语言不同),因为如果从该枚举中间添加或删除一个成员,所有后续成员的值都会改变。这可能不安全(例如,推送安全、序列化、日志记录)。要求用户明确地重新编号,让他们考虑这样做带来的后果。

提供的值必须是数字文字。(注意:JavaScript 中没有负数的文字,它们是将一元 - 操作应用于数字文字的结果。)如果出现需要扩展允许值的请求,我们将来可能会扩展允许的值以包含某些非文字。

布尔值枚举

布尔值枚举必须指定其值。布尔值枚举只能有两个成员。

您可以像这样指定布尔值枚举

1enum Status {2  Active = true,3  Off = false,4}

您可以选择使用 of 子句。这不会影响有效 Flow 枚举的类型检查行为,它只是确保所有枚举成员在定义位置都是 boolean

1enum Status of boolean {2  Active = true,3  Off = false,4}

符号枚举

符号枚举不能指定其值。每个成员都是一个新的符号,符号描述设置为成员的名称。您必须在符号枚举中使用 of 子句,以将其与字符串枚举区分开来,字符串枚举是省略值时的默认值。

您可以像这样指定符号枚举

1enum Status of symbol {2  Active,3  Paused,4  Off,5}

具有未知成员的 Flow 枚举

您可以通过在声明末尾添加 ... 来指定您的枚举包含“未知成员”

1enum Status {2  Active,3  Paused,4  Off,5  ...6}7const status: Status = Status.Active;8
9switch (status) {
10 case Status.Active: break;11 case Status.Paused: break;12 case Status.Off: break;13}
9:9-9:14: Missing `default` case in the check of `status`. `Status` [1] has unknown members (specified using `...`) so checking it requires the use of a `default` case to cover those members. [invalid-exhaustive-check]

使用此方法时,Flow 将始终在 枚举上进行切换 时要求使用 default,即使检查了所有已知的枚举成员。default 检查您没有显式列出的“未知”成员。

当枚举值跨越某个边界,并且每侧的枚举声明可能具有不同的成员时,此功能很有用。例如,在客户端和服务器上都使用的枚举定义:可以添加一个枚举成员,该成员会立即被服务器看到,但可以发送到尚未了解新成员的过时客户端。

此功能的一个用例是 GraphQL 枚举 的 JS 输出:可以使用具有未知成员的 Flow 枚举来代替添加的 '%future added value' 成员。

运行时的枚举

枚举在运行时作为值存在。我们使用 Babel 转换 将 Flow 枚举声明转换为对 枚举运行时 的调用(在 启用枚举文档 中了解更多信息)。我们使用运行时,以便所有枚举都可以共享枚举 方法 的实现。

我们使用 Object.create(null) 作为枚举的原型(它具有枚举方法),因此 Object.prototype 中的属性不会污染枚举。枚举对象的唯一自有属性是枚举成员。成员不可枚举(为此使用 .members() 方法)。整个枚举对象被冻结,因此它不能被修改。

风格指南

命名枚举

我们鼓励您使用 PascalCase 定义枚举名称,遵循其他类型的命名约定。全大写名称(例如,STATUS)更难阅读,因此不建议使用。

我们鼓励您使用单数形式命名枚举。例如,Status,而不是 Statuses。就像 truefalse 的类型是 boolean,而不是 booleans 一样。

不要在名称后面添加 Enum(例如,不要将您的枚举命名为 StatusEnum)。这是不必要的,就像我们不会在每个类名后面添加 Class,也不会在每个类型别名后面添加 Type 一样。

命名枚举成员

我们鼓励您使用 PascalCase 定义枚举成员名称。全大写名称(例如,ACTIVE)更难阅读,因此不建议使用。此外,由于 Flow 强制执行这些是常量,因此您不需要使用名称来向程序员传达这种意图。

另请参阅:关于 枚举成员名称起始字符 的规则。

不要创建单独的类型

Flow 枚举,就像类一样,既是类型又是值。您不需要创建单独的类型别名,您可以使用枚举名称。

使用点访问来访问成员

优先使用 Status.Active 而不是 const {Active} = Status;。这使得使用文本搜索更容易找到枚举的使用情况,并且使读者更清楚地了解涉及的枚举。此外,这是 涉及枚举的 switch 语句 所必需的。