使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。枚举类型使用 enum 关键字。
枚举的类型
数字枚举 Numeric enums
export enum Day {
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
字符串枚举 String enums
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
异构枚举 Heterogeneous enums
数字类型和字符串类型可以混合使用,但是不建议:
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
枚举成员
计算成员和常量成员 Computed and constant members
enum FileAccess {
// constant members
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// computed member
G = "123".length,
}
Union enums and enum member types
运行时和编译时
枚举在运行时 Enums at runtime
枚举是在运行时真正存在的对象,可以被传递到方法中:
enum E {
X,
Y,
Z,
}
function f(obj: { X: number }) {
return obj.X;
}
// works, E含有X属性
f(E);
枚举在编译时 Enums at compile time
即使枚举是在运行时存在的真实对象,关键字 keyof
与对象的运行方式又是不同的。我们使用 keyof typeof
来获得一个将所有Enum键表示为字符串的类型。
enum LogLevel {
ERROR,
WARN,
INFO,
DEBUG,
}
/**
* This is equivalent to:
* type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
*/
type LogLevelStrings = keyof typeof LogLevel;
function printImportant(key: LogLevelStrings, message: string) {
const num = LogLevel[key];
if (num <= LogLevel.WARN) {
console.log("Log level key is:", key);
console.log("Log level value is:", num);
console.log("Log level message is:", message);
}
}
printImportant("ERROR", "This is a message");
正向映射和反向映射
数字枚举成员具有反向映射:
enum Enum {
A,
}
let a = Enum.A; // 0
let nameOfA = Enum[a]; // "A"
TypeScript可能会将这段代码编译为下面的JavaScript:
"use strict";
var Enum;
(function (Enum) {
Enum[Enum["A"] = 0] = "A";
})(Enum || (Enum = {}));
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
生成的代码中,枚举类型被编译成一个对象,它包含了正向映射( name -> value)和反向映射( value -> name)。
要注意的是:不会为字符串枚举成员生成反向映射。
枚举的定义
enum
当我们定义一个枚举
enum Cheese { Brie, Cheddar }
编译器将编译为:
var Cheese;
(function (Cheese) {
Cheese[Cheese["Brie"] = 0] = "Brie";
Cheese[Cheese["Cheddar"] = 1] = "Cheddar";
})(Cheese || (Cheese = {}));
所以我们可以正向映射或反向映射:
// Evaluates to 0 at runtime
Cheese.Brie;
// Evaluates to 'Brie' at runtime
Cheese[0];
const enum
当我们定义一个const枚举:
const enum Bread { Rye, Wheat }
不会有任何代码编译输出。只有当我们访问:
const rye = Bread.Rye
// or
const rye = Bread['Rye']
只剩下常量 rye
。当如果你访问:
// Compiler error. const enums don't provide reverse lookup.
// Bread[0]
运行时就会报错。
Note:如果tsconfig 打开配置项 --preserveConstEnums
,编译结果将会和定义普通enum一样。
declare enum
官方文档也叫 Ambient enums
定义一个外部枚举:
declare enum Wine { Red, Wine }
也不会编译出任何代码。它是用来描述已经存在的枚举类型的形状。
declare const enum
declare const enum Fruit { Apple, Pear }
Objects vs Enums
const enum EDirection {
Up,
Down,
Left,
Right,
}
const ODirection = {
Up: 0,
Down: 1,
Left: 2,
Right: 3,
} as const;
EDirection.Up;
// ^ = (enum member) EDirection.Up = 0
ODirection.Up;
// ^ = (property) Up: 0
// Using the enum as a parameter
function walk(dir: EDirection) {}
// It requires an extra line to pull out the keys
type Direction = typeof ODirection[keyof typeof ODirection];
function run(dir: Direction) {}
walk(EDirection.Left);
run(ODirection.Right);
参考:
- Enums (官方英文文档)
- 枚举
- TypeScript enums explained (比较了enum, const enum, declare enum, and declare const enum identifiers.)