这是我参与11月更文挑战的第 7 天,活动详情查看:2021最后一次更文挑战
使用枚举我们可以定义一些带名字的常量。使用枚举可以清晰地表达意图或创建一组有区别的用例。TypeScript支持数字的和基于字符串的枚举。
数字枚举
比如,我们定义一个数字枚举, Up使用初始化为 1,其余的成员会从 1 开始自动增长。
enum Direction {
Up = 1,
Down,
Left = 5,
Right
}
let c: Direction = Direction.Up;
let d: Direction = Direction.Down;
let e: Direction = Direction.Left;
let f: Direction = Direction.Right;
console.log(c,d,e,f) //1 2 5 6
不初始化Up时,Up的值为 0,Down的值为1,依此类推。
字符串枚举
在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
字符串枚举没有自增长的行为。
使用枚举
我们可以通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型:
enum MyEnum { No, Yes }
function respond(recipient: string, message: MyEnum): void {
// ...
}
respond("Princess Caroline", MyEnum.Yes)
enum Color {Red, Green, Blue}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
console.log(c,d,e) // 0,1,2
枚举成员
每个枚举成员都带有一个值,它可以是 常量或 计算出来的。
枚举成员使用常量枚举表达式进行初始化。当一个表达式满足下面条件之一时,它就是一个常量枚举表达式:
- 一个枚举表达式字面量(主要是字符串字面量或数字字面量)
- 一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)
- 带括号的常量枚举表达式
- 一元运算符
+,-,~其中之一应用在了常量枚举表达式 - 常量枚举表达式做为二元运算符
+,-,*,/,%,<<,>>,>>>,&,|,^的操作对象。 若常数枚举表达式求值后为NaN或Infinity,则会在编译阶段报错。
enum FileAccess {
// constant members
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// computed member
G = "123".length
}
当枚举成员的值包含字符串时,不允许在后续的枚举值中使用表达式进行计算:
enum Color {Red="hh", Green = Math.random(), Blue=4}
// error! Computed values are not permitted in an enum with string valued members.
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
console.log(c,d,e) // "hh", 0, 4
枚举成员的类型与联合枚举
字面量枚举成员是指不带有初始值的常量枚举成员,或者是值被初始化为
- 任何字符串字面量(例如:
"foo","bar","baz") - 任何数字字面量(例如:
1,100) - 应用了一元
-符号的数字字面量(例如:-1,-100)
当所有枚举成员都拥有字面量枚举值时,它就带有了一种特殊的语义。
首先,枚举成员成为了类型 !
enum ShapeKind {
Circle,
Square
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
interface Square {
kind: ShapeKind.Square;
sideLength: number;
}
let c: Circle = {
kind: ShapeKind.Square, // 这里,枚举成员ShapeKind.Square是类型
// Error! Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'.
radius: 100,
}
其次,枚举类型本身变成了每个枚举成员的联合。
enum E {
Foo,
Bar,
}
function f(x: E) {
if (x !== E.Foo || x !== E.Bar) { // 永远为true。
// ~~~~~~~~~~~
// Error! This condition will always return 'true' since the types 'E.Foo' and 'E.Bar' have no overlap.
}
}
运行时的枚举
枚举是在运行时真正存在的对象。 例如下面的枚举:
enum E {
X, Y, Z
}
function f(obj: { X: number }) {
return obj.X;
}
f(E); // Works, since 'E' has a property named 'X' which is a number.
反向映射
除了创建一个以属性名做为对象成员的对象之外,数字枚举成员还具有了反向映射,从枚举值到枚举名字。
enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
enum Color {Red, Green, Blue = 4}
let c: string = Color[0];
let d: string = Color[1];
let e: string = Color[2];
console.log(c,d,e) // "Red", "Green", undefined
const枚举
const 定义的枚举,在经过编译器编译后是一个对象,这个对象我们可以在程序运行时使用。
const enum E {
Foo,
Bar,
}
let num1: E = E.Foo
enum F {
Foo,
Bar,
}
let num2: F = F.Foo
编译结果:
let num1 = 0 /* Foo */;
var F;
(function (F) {
F[F["Foo"] = 0] = "Foo";
F[F["Bar"] = 1] = "Bar";
})(F || (F = {}));
let num2 = F.Foo;
可以看到编译后的代码中,const枚举直接用 0 进行替代,这样就节省了生成代码的开销。
declare枚举
外部枚举(declare枚举)用来描述已经存在的枚举类型。
declare enum Enum {
A = 1,
B,
C = 2
}
外部枚举和非外部枚举之间有一个重要的区别,在正常的枚举里,没有初始化方法的成员被当成常数成员。 对于非常数的外部枚举而言,没有初始化方法时被当做需要经过计算的。
外部枚举类似于类型断言,只要有这个声明,意味着在当前开发环境上下文中一定存在当前这个对象,ts 类型系统能够侦测到当前整个文件目录上下文中的所有 declare 声明的变量,因此你可以随意使用当前对象。