Pasoul / blog

🛠 学习笔记 & 源码分析 & 代码规范 & 数据结构与算法
17 stars 3 forks source link

typescript手册-枚举 #22

Open Pasoul opened 5 years ago

Pasoul commented 5 years ago

枚举通常用于取值限定在一定范围的场景,比如一周只有七天,颜色被限定为红绿蓝等。

简单的例子

枚举使用enum关键字来定义

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

枚举成员默认被赋值为从0开始递增的数字,同时也可以从枚举值反向映射到枚举名

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

console.log(Days['Sun']); // 0
console.log(Days['Mon']); // 1
console.log(Days['Tue']); // 2
console.log(Days['0']); // Sun
console.log(Days['1']); // Mon
console.log(Days['2']); // Tue

我们来看编译后的代码,如果让我们实现一个对象的属性和属性值之间的映射,大家应该知道怎么做了

var Days;
(function (Days) {
    Days[Days["Sun"] = 0] = "Sun";
    Days[Days["Mon"] = 1] = "Mon";
    Days[Days["Tue"] = 2] = "Tue";
    Days[Days["Wed"] = 3] = "Wed";
    Days[Days["Thu"] = 4] = "Thu";
    Days[Days["Fri"] = 5] = "Fri";
    Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));

手动赋值

我们也可以给枚举项手动赋值,typescript只支持枚举值为数字字符串类型

数字字面量

enum Days {Sun = 7, Mon = 2, Tue, Wed, Thu, Fri, Sat};

console.log(Days['Sun']);// 7
console.log(Days['Mon']);// 2
console.log(Days['Tue']);// 3
console.log(Days['Wed']);// 4
console.log(Days['Sat']);// 7
console.log(Days['0']);// undefined
console.log(Days['1']);// undefined
console.log(Days['2']);// Mon
console.log(Days['3']);// Tue
console.log(Days['7']);// Sat

上面的例子中,我们未手动赋值枚举项会接着上一个枚举项的值递增。

我们注意到未赋值的最后一项和手动赋值的第一项冲突了,但是typescript不会察觉到,所以Days['7']的值会被覆盖,编译结果是:

var Days;
(function (Days) {
    Days[Days["Sun"] = 7] = "Sun";
    Days[Days["Mon"] = 2] = "Mon";
    Days[Days["Tue"] = 3] = "Tue";
    Days[Days["Wed"] = 4] = "Wed";
    Days[Days["Thu"] = 5] = "Thu";
    Days[Days["Fri"] = 6] = "Fri";
    Days[Days["Sat"] = 7] = "Sat";
})(Days || (Days = {}));

所以在实际使用中我们应该避免出现覆盖的情况。

我们也可以给枚举项赋值为负数、小数:

// 小数
enum Days {Sun = 7, Mon = 2.5, Tue, Wed, Thu, Fri, Sat};

console.log(Days['Sun']); // 7
console.log(Days['Mon']); // 2.5
console.log(Days['Tue']); // 3.5
console.log(Days['Sat']); // 7.5
// 负数
enum Days {Sun = 7, Mon = -2, Tue, Wed, Thu, Fri, Sat};

console.log(Days['Sun']); // 7
console.log(Days['Mon']); // -2
console.log(Days['Tue']); // -1
console.log(Days['Sat']); // 3

我们可以看到无论是前面手动赋值类型是正整数、小数还是负数,未赋值项的递增步长仍然为1。

字符串字面量

手动给枚举项赋值的类型也可以是string:

enum Days {Sun = 7, Mon = 2, Tue, Wed, Thu, Fri, Sat = 'S'};

console.log(Days['Fri']); // 6
console.log(Days['Sat']); // S

需要注意的是,string类型的枚举项后面不能存在其他枚举项,比如:

enum Days {Sun = 7, Mon = 2, Tue, Wed, Thu, Fri = 'F', Sat};

console.log(Days['Fri']); // F
console.log(Days['Sat']); // undefined
// 编译报错:Enum member must have initializer.

这里typescript提示枚举成员必须具有初始化表达式,意思是说我们必须给Fri = 'F'后面的枚举项也手动赋值。

Pasoul commented 5 years ago

常量项和计算所得项

每个枚举项都会有值,这个值只有两种类型:常量和计算出来的。

当满足以下几个条件之一时,枚举项被当做是常量

当一个表达式满足下面条件之一时,它就是一个常量枚举表达式:

所有其它情况的枚举成员被当作是需要计算得出的值。这里X,Y是常量项,Z是计算所得项

enum Days {X , Y , Z = 'abc'.length}

Pasoul commented 5 years ago

const枚举

常数枚举是在枚举前面加上const声明,一般情况下在不希望生成额外的代码开销下使用。因为编译的过程中会被删除。

const enum Directions {
  Up,
  Down,
  Left,
  Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

编译结果: var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

常数枚举不能包含计算成员:

const enum Directions {
  Up,
  Down,
  Left,
  Right = 'abc'.length
}
// In 'const' enum declarations member initializer must be constant expression

参考: