枚举
988字约3分钟
TypeScript
2023-01-30
TypeScript 枚举类型用关键字 enum
声明。
// 编译前
enum Color {
Red, // 0
Green, // 1
Blue, // 2
}
// 编译后
let Color = {
Red: 0,
Green: 1,
Blue: 2,
};
注意
绝大多数 TypeScript 语法都是类型语法,编译后会全部去除,但是 Enum 结构是一个值,编译后会变成 JavaScript 对象,留在代码中。
另外,由于 Enum 结构编译后是一个对象,所以不能有与它同名的变量(包括对象、函数、类等)。
✨Enum 成员的值
(1) Enum 成员默认不必赋值,系统会从零开始逐一递增,按照顺序为每个成员赋值,比如 0、1、2……。
详情
enum Color {
Red,
Green,
Blue,
}
// 等同于
enum Color {
Red = 0,
Green = 1,
Blue = 2,
}
(2) 成员的值可以是任意数值,成员的值甚至可以相同,但不能是大整数(Bigint)。
详情
enum Color {
Red = 90,
Green = 0.5,
Blue = 7n, // 报错
}
(3) 如果只设定第一个成员的值,后面成员的值就会从这个值开始递增。
详情
enum Color {
Red = 7,
Green, // 8
Blue, // 9
}
// 或者
enum Color {
Red, // 0
Green = 7,
Blue, // 8
}
(4) Enum 成员的值也可以使用计算式。
详情
enum Permission {
UserRead = 1 << 8,
UserWrite = 1 << 7,
UserExecute = 1 << 6,
GroupRead = 1 << 5,
GroupWrite = 1 << 4,
GroupExecute = 1 << 3,
AllRead = 1 << 2,
AllWrite = 1 << 1,
AllExecute = 1 << 0,
}
enum Bool {
No = 123,
Yes = Math.random(),
}
(5) Enum 成员值都是只读的,不能重新赋值。为了让这一点更醒目,通常会在 enum
关键字前面加上 const
修饰,表示这是常量,不能再次赋值。
加上 const
还有一个好处,就是编译为 JavaScript 代码后,代码中 Enum
成员会被替换成对应的值,这样能提高性能表现。
如果希望加上 const
关键词后,运行时还能访问 Enum 结构(即编译后依然将 Enum 转成对象),需要在编译时打开 preserveConstEnums
编译选项。
✨同名 Enum 的合并
多个同名的 Enum 结构会自动合并。
合并的限制:
Enum 结构合并时,只允许其中一个的首成员省略初始值,否则报错。
同名 Enum 合并时,不能有同名成员,否则报错。
同名 Enum 合并的另一个限制是,所有定义必须同为 const 枚举或者非 const 枚举,不允许混合使用。
✨字符串 Enum
Enum 成员的值除了设为数值,还可以设为字符串。也就是说,Enum 也可以用作一组相关字符串的集合。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
字符串 Enum 限制:
- 字符串枚举的所有成员值,都必须显式设置。如果没有设置,成员值默认为数值,且位置必须在字符串成员之前。
详情
enum Foo {
A, // 0
B = "hello",
C, // 报错
}
- Enum 成员可以是字符串和数值混合赋值。除了数值和字符串,Enum 成员不允许使用其他值(比如 Symbol 值)。
详情
enum Enum {
One = "One",
Two = "Two",
Three = 3,
Four = 4,
}
- 字符串 Enum 的成员值,不能使用表达式赋值。
详情
enum MyEnum {
A = "one",
B = ["T", "w", "o"].join(""), // 报错
}
✨keyof 运算符
keyof
运算符可以取出 Enum 结构的所有成员名,作为联合类型返回。
enum MyEnum {
A = "a",
B = "b",
}
// 'A'|'B'
// 注意,这里的typeof是必需的,否则keyof MyEnum相当于keyof number。
type Foo = keyof typeof MyEnum;
如果要返回 Enum 所有的成员值,可以采用属性索引可以取出MyEnum的所有成员值。
enum MyEnum {
A = "a",
B = "b",
}
// { a:any, b: any }
type Foo = { [key in MyEnum]: any };
✨反向映射
数值 Enum 存在反向映射,即可以通过成员值获得成员名。
enum Weekdays {
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}
console.log(Weekdays[3]); // Wednesday
注意
注意,这种情况只发生在数值 Enum,对于字符串 Enum,不存在反向映射。这是因为字符串 Enum 编译后只有一组赋值。