使用enum关键字可以定义枚举

数字枚举

枚举默认从0开始,每个成员都表示一个数字

1
2
3
4
5
6
enum Color {
red,
green,
blue
}
console.log(Color.red,Color.green,Color.blue) // ->0 1 2

可以给成员赋值,没赋值的成员,默认值就是上一个成员的值+1

1
2
3
4
5
6
7
8
9
10
11
12
13
enum Color {
red = -1,
green,
blue
}
console.log(Color.red,Color.green,Color.blue) // ->-1 0 1

enum Color2 {
red = 2.3,
green,
blue = 2
}
console.log(Color2.red,Color2.green,Color2.blue) // ->2.3 3.3 2

字符串枚举

枚举中的每个成员都赋值为字符串时,就是字符串枚举

1
2
3
4
5
6
7
8
enum Color {
red = "red",
green = "green",
// 字符串枚举必须给每一项都赋值
// blue = "blue" // 不OK
blue = "blue",
}
console.log(Color.red,Color.green,Color.blue) // ->-"red" "green" "blue"

字符串枚举没有自增长的行为,所以字符串枚举可以很好的序列化,从语义上讲比数字枚举更有意义

异构枚举

枚举时可以混合字符串和数字成员

赋值为字符串的成员,之后的成员必须赋值,因为字符串影响了默认值的递增

1
2
3
4
5
6
7
8
9
10
enum Types{
aa,
bb = 5,
cc,
No = "No",
// 不能使用,因为dd前面有一个成员的值是字符串
// dd,
Yes = 1,
}
console.log(Types.aa,Types.bb,Types.cc,Types.No,Types.Yes) // -> 0 5 6 "No" 1

接口枚举

接口和枚举可以复合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Types{
No = "No",
Yes = 1,
}

interface A {
red: Types.Yes
green: Types.No
}

let obj:A = {
// red: "aaa", // 不OK
red: 1, // OK
green: Types.No // OK
}

const枚举

const枚举在编译后会直接变成常量

编译前:

1
2
3
4
5
6
7
const enum Types{
success,
fail
}

let code = 0
if(code === Types.success) {}

编译后:

1
2
3
let code = 0;
// 直接把Types.success编译成0(具体的值)了
if (code === 0 /* Types.success */) {}

如果不加const关键字,枚举会被编译成:

1
2
3
4
5
6
7
8
9
10
var Types;
(function (Types) {
Types[Types["success"] = 0] = "success";
Types[Types["fail"] = 1] = "fail";
})(Types || (Types = {}));

let code = 0;
if (code === Types.success) {}

console.log(Types) // ->{ '0': 'success', '1': 'fail', success: 0, fail: 1 }

反向映射

正向映射是key→value,那么反向映射就是value→key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Types{
success = 114,
fail = "fff"
}

// 不仅可以通过成员名读值(正向映射)
let success:number = Types.success
// 也可以通过值读成员名(反向映射)
let skey = Types[success]

// 但字符串枚举成员无法进行反向映射
let fail:string = Types.fail
let fkey = Types[fail]

console.log(success, skey, fail, fkey) // -> 114 "success" "fff" undefined

编译后:

1
2
3
4
5
6
7
8
9
10
11
12
var Types;
(function (Types) {
Types[Types["success"] = 114] = "success";
// 没有进行Types[fff]="fail"的赋值
Types["fail"] = "fff";
})(Types || (Types = {}));

let success = Types.success;
let skey = Types[success];

let fail = Types.fail;
let fkey = Types[fail];

如果枚举中出现数字值重复,那么使用反向映射时可能会出问题:

1
2
3
4
5
6
7
8
9
10
11
12
enum Types{
success = 114,
fail = 114
}

let success:number = Types.success
let skey = Types[success]

let fail:number = Types.fail
let fkey = Types[fail]

console.log(success, skey, fail, fkey) // -> 114 "fail" 114 "fail"

因为编译后出现了对象键值的覆盖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Types;
(function (Types) {
// 114键被赋值了两次
Types[Types["success"] = 114] = "success";
Types[Types["fail"] = 114] = "fail";
})(Types || (Types = {}));

let success = Types.success;
let skey = Types[success];

let fail = Types.fail;
let fkey = Types[fail];

console.log(Types) // ->{ '114': 'fail', success: 114, fail: 114 }