使用枚举我们可以定义一些带名字的常量。TypeScript 支持数字的和基于字符串的枚举。
数字枚举
声明一个枚举类型,如果没有赋值,它们的值默认为数字类型且从 0 开始累加:
enum Months {
Jan,
Feb,
Mar,
Apr
}
Months.Jan === 0 // true
Months.Feb === 1 // true
Months.Mar === 2 // true
Months.Apr === 3 // true
// 如果从第一个数字赋值,往后值依次累加
enum Months {
Jan = 1,
Feb,
Mar,
Apr
}
Months.Jan === 1 // true
Months.Feb === 2 // true
Months.Mar === 3 // true
Months.Apr === 4 // true
字符串枚举
enum TokenType {
ACCESS = 'accessToken',
REFRESH = 'refreshToken'
}
// 两种不同的取值写法
console.log(TokenType.ACCESS === 'accessToken') // true
console.log(TokenType['REFRESH'] === 'refreshToken') // true
异构枚举
数字类型和字符串类型可以混合使用,但是不建议
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
计算的和常量成员
每个枚举成员都带有一个值,它可以是常量或计算出来的。
当满足如下条件时,枚举成员被当作是常量:
- 枚举的第一个成员且没有初始化器,这种情况下它被赋予值 0:
enum E { X } // E.X is constant
- 枚举成员不带初始化器,但是它前一个枚举成员使用了常数来初始化:
//All enum members in 'E1' and 'E2' are constant.
enum E1 { X, Y, Z }
enum E2 {
A = 1, B, C
}
- 枚举成员使用常量枚举表达式初始化。
常量枚举表达式是TypeScript表达式的子集,它可以在编译阶段求值。 当一个表达式满足下面条件之一时,它就是一个常量枚举表达式:
- 一个枚举表达式字面量(主要是字符串字面量或数字字面量)
enum E1 { one = 10, two, three }
enum E2 { one = 'one', two='two', three='three'}
- 一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)
// one 是对E2.one的引用,two 是对当前枚举成员one的引用
enum E3 { one = E2.one, two = 2 * one }
- 带括号的常量枚举表达式
//即可以是函数的调用,也可以是计算表达式的求值
function returnNumber (x: number): number {
return x
}
enum E4 {
one = (function () { return 1 })(),
two = returnNumber(10),
three = (E1.one + E1.two) % E1.three
}
- 一元运算符
+, -, ~
其中之一应用在了常量枚举表达式
enum E5 {
one = ~E1.one,// 取反运算
two = +E1.two,
three = -E1.three,
four = void 0
}
- 常量枚举表达式做为二元运算符
+, -, *, /, %, <<, >>, >>>, &, |, ^
的操作对象。
enum E6 {
// 左移运算
one = 2 << 5,
// 右移运算
two = 64 >> 5,
three = 64 >>> 5,
// 或 运算合并 乘性运算
four = (one | two) * three
}
所有其它情况的枚举成员被当作是需要计算得出的值:
enum FileAccess {
// constant members
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// computed member
G = "123".length
}
反向映射
所谓的反向映射就是指枚举的取值,不但可以正向的 Months.Jan 这样取值,也可以反向的 Months[1] 这样取值。
enum Months {
Jan = 1,
Feb,
Mar,
Apr
}
console.log(Months.Mar === 3) // true
console.log(Months[3] === 'Mar') // true
编译后的 JavaScript 代码:
'use strict'
var Months;
(function (Months) {
Months[Months['Jan'] = 1] = 'Jan'
Months[Months['Feb'] = 2] = 'Feb'
Months[Months['Mar'] = 3] = 'Mar'
Months[Months['Apr'] = 4] = 'Apr'
})(Months || (Months = {}))
Tips:
- 字符串枚举成员不会生成反向映射。
- 枚举类型被编译成一个对象,它包含了正向映射( name -> value)和反向映射( value -> name)。
const 枚举
在枚举上使用 const 修饰符:
enum Months {
Jan = 1,
Feb,
Mar,
Apr
}
const month = Months.Mar
编译后的内容:
'use strict'
const month = 3 /* Mar */
枚举类型应该编译出的对象没有了,只剩下 month 常量。这就是使用 const 关键字声明枚举的作用。因为变量 month 已经使用过枚举类型,在编译阶段 TypeScript 就将枚举类型抹去,这也是性能提升的一种方案。
枚举合并
分开声明名称相同的枚举类型,会自动合并:
enum Months {
Jan = 1,
Feb,
Mar,
Apr
}
enum Months {
May = 5,
Jun
}
console.log(Months.Apr) // 4
console.log(Months.Jun) // 6