5.4.6 联合枚举类型

当枚举类型中的所有成员都是字面量枚举成员时,该枚举类型成了联合枚举类型。

5.4.6.1 联合枚举成员类型

联合枚举类型中的枚举成员除了能够表示一个常量值外,还能够表示一种类型,即联合枚举成员类型。

下例中,Direction枚举是联合枚举类型,Direction枚举成员Up、Down、Left和Right既表示数值常量,也表示联合枚举成员类型:


01 enum Direction {
02     Up,
03     Down,
04     Left,
05     Right,
06 }
07 
08 const up: Direction.Up = Direction.Up;

此例第8行,第一个“Direction.Up”表示联合枚举成员类型,第二个“Direction.Up”则表示数值常量0。

联合枚举成员类型是联合枚举类型的子类型,因此可以将联合枚举成员类型赋值给联合枚举类型。示例如下:


01 enum Direction {
02     Up,
03     Down,
04     Left,
05     Right,
06 }
07 
08 const up: Direction.Up = Direction.Up;
09 
10 const direction: Direction = up;

此例中,常量up的类型是联合枚举成员类型“Direction.Up”,常量direction的类型是联合枚举类型Direction。由于“Direction.Up”类型是Direction类型的子类型,因此可以将常量up赋值给常量direction。

5.4.6.2 联合枚举类型

联合枚举类型是由所有联合枚举成员类型构成的联合类型。示例如下:


01 enum Direction {
02     Up,
03     Down,
04     Left,
05     Right,
06 }
07 
08 type UnionDirectionType =
09     | Direction.Up
10     | Direction.Down
11     | Direction.Left
12     | Direction.Right;

此例中,Direction枚举是联合枚举类型,它等同于联合类型UnionDirectionType,其中“|”符号是定义联合类型的语法。关于联合类型的详细介绍请参考6.3节。

由于联合枚举类型是由固定数量的联合枚举成员类型构成的联合类型,因此编译器能够利用该性质对代码进行类型检查。示例如下:


01 enum Direction {
02     Up,
03     Down,
04     Left,
05     Right,
06 }
07 
08 function f(direction: Direction) {
09     if (direction === Direction.Up) {
10         // Direction.Up
11     } else if (direction === Direction.Down) {
12         // Direction.Down
13     } else if (direction === Direction.Left) {
14         // Direction.Left
15     } else {
16         // 能够分析出此处的direction为Direction.Right
17         direction;
18     }
19 }

此例中,编译器能够分析出Direction联合枚举类型只包含四种可能的联合枚举成员类型。在“if-else”语句中,编译器能够根据控制流分析出最后的else分支中direction的类型为“Direction.Right”。

下面再来看另外一个例子。Foo联合枚举类型由两个联合枚举成员类型“Foo.A”和“Foo.B”构成。编译器能够检查出在第7行if条件判断语句中的条件表达式结果永远为true,因此将产生编译错误。示例如下:


01 enum Foo {
02     A = 'A',
03     B = 'B',
04 }
05 
06 function bar(foo: Foo) {
07     if (foo !== Foo.A || foo !== Foo.B) {
08         //               ~~~~~~~~~~~~~
09         //               编译错误:该条件永远为'true'
10     }
11 }

让我们继续深入联合枚举类型。下例中,由于Foo联合枚举类型等同于联合类型“Foo.A | Foo.B”,因此它是联合类型“'A' | 'B'”的子类型:


01 enum Foo {
02     A = 'A',
03     B = 'B',
04 }
05 
06 enum Bar {
07     A = 'A',
08 }
09 
10 enum Baz {
11     B = 'B',
12     C = 'C',
13 }
14 
15 function f1(x: 'A' | 'B') {
16     console.log(x);
17 }
18 
19 function f2(foo: Foo, bar: Bar, baz: Baz) {
20     f1(foo);
21     f1(bar);
22 
23     f1(baz);
24     // ~~~
25     // 错误:类型 'Baz' 不能赋值给参数类型'A' | 'B'
26 }

此例第15行,f1函数接受“'A' | 'B'”联合类型的参数x。第20行,允许使用Foo枚举类型的参数foo调用函数f1,因为Foo枚举类型是“'A' | 'B'”类型的子类型。第21行,允许使用Bar枚举类型的参数bar调用函数f1,因为Bar枚举类型是'A'类型的子类型,显然也是“'A' | 'B'”类型的子类型。第23行,不允许使用Baz枚举类型的参数baz调用函数f1,因为Baz枚举类型是“'B' | 'C'”类型的子类型,显然与“'A' | 'B'”类型不兼容,所以会产生错误。

关于子类型兼容性的详细介绍请参考7.1节。