一、概念
使用枚举我们可以定义一些带名字的常量。
我理解的是使用枚举,可以解决我们在项目中定义常量不规范的问题。
- 数字枚举
// 使用初始化器
enum Direction { // 定义数字枚举
Up = 1, // 使用初始化器,初始值1
Down, // 2
Left, // 3
Right // 4
// ...定义依次递增
}
// 不使用初始化器
enum Direction {
Up, // 0
Down, // 1
Left,
Right,
}
通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型
enum Response {
No = 0,
Yes = 1,
}
function respond(recipient: string, message: Response): void {
console.log(recipient + ' ' + message);
}
respond("Princess Caroline", Response.Yes) // Princess Caroline 1
respond("Princess Caroline", 1000) // Princess Caroline 1000 这里值没有在Response里定义也不报错
respond("Princess Caroline", 'df') // error 类型“"df"”的参数不能赋给类型“Response”的参数。ts(2345)
数字枚举中使用函数计算得出的常量成员,后面紧跟着的常量成员必须使用常量进行初始化。
function getSomeValue(): number {
return 123
}
enum E {
A = getSomeValue(),
B = 1, // error! 前面的'A'不是常量初始化的,所以'B'需要一个初始化器
C // 2 no error
}
- 字符串枚举
在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
- 异构枚举
enum BooleanLikeHeterogeneousEnum { // 不建议这样使用
No = 0,
Yes = "YES",
}
- 计算的成员和常量成员
- 它是枚举的第一个成员且没有初始化器,这种情况下它被赋予值 0
// E.X is constant:
enum E {
X // 0
}
- 它不带有初始化器且它之前的枚举成员是一个 数字常量。 这种情况下,当前枚举成员的值为它上一个枚举成员的值加1。
enum E2 {
A = 1,
B, // 2
C // 3
}
- 枚举成员使用 常量枚举表达式初始化。
使用规则:
一个枚举表达式字面量(主要是字符串字面量或数字字面量)
一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)
带括号的常量枚举表达式
一元运算符 +, -, ~其中之一应用在了常量枚举表达式
常量枚举表达式做为二元运算符 +, -, *, /, %, <<, >>, >>>, &, |, ^的操作对象
若常数枚举表达式求值后为 NaN或 Infinity,则会在编译阶段报错。
enum FileAccess {
// constant members
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// computed member
G = "123".length
}
- 枚举成员成为类型
enum ShapeKind {
Circle,
Square,
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
interface Square {
kind: ShapeKind.Square;
sideLength: number;
}
let c: Circle = {
kind: ShapeKind.Square, // Error!
// kind: 1, no error
// kind: 123, no error
// kind: 'str', // 不能将类型“string”分配给类型“ShapeKind.Circle”。
radius: 100,
}
短路问题
enum E {
Foo,
Bar
}
function f(x: E) {
if (x !== E.Foo || x !== E.Bar) { // 判断无意义,总是会通过第一个判断
// ~~~~~~~~~~~
// Error! Operator '!==' cannot be applied to types 'E.Foo' and 'E.Bar'.
console.log(x);
}
}
- 将枚举当作参数传入函数中
枚举对象
enum E {
X, Y, Z
}
function f(obj: { X: number }) {
return obj.X; // Works, since 'E' has a property named 'X' which is a number.
}
console.log(f(E)); // 0
反向映射:从枚举值到枚举名字。
enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
生成的代码中,枚举类型被编译成一个对象,它包含了正向映射( name -> value)和反向映射( value -> name)。 引用枚举成员总会生成为对属性访问并且永远也不会内联代码。
要注意的是 不会为字符串枚举成员生成反向映射。
- const枚举
减少重复代码定义产生的代码量开销
避免非直接的对枚举成员的访问
const enum Enum {
A = 1,
B = A * 2
}
常量枚举只能使用常量枚举表达式,并且不同于常规的枚举,它们在编译阶段会被删除。
常量枚举成员在使用的地方会被内联进来。
常量枚举不允许包含计算成员。
// 使用常量枚举
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right] // [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */]
// 使用计算初始化枚举成员
function getval() {
return 123
}
enum Directions {
Up = getval(),
Down = 1
}
let directions = [Directions.Up, Directions.Down] // [123, 1]
- 外部枚举
外部枚举用来描述已经存在的枚举类型的形状。
declare enum Enum { // 没有完全弄懂这个declare,据网上博文描述,
A = 1,
B,
C = 2
}
外部枚举和非外部枚举之间有一个重要的区别,在正常的枚举里,没有初始化方法的成员被当成常数成员。 对于非常数的外部枚举而言,没有初始化方法时被当做需要经过计算的。