TS-枚举类型enum
·
- 枚举的作用是列举类型中包含的各个值,一般用它来管理多个相同系列的常量(即不能被修改的变量),用于状态的判断。这是一种无序的数据结构,把键映射到值上,可以理解为编译时键固定的对象,访问键时,ts将检查指定的键是否存在
在web中,比较常见的状态判断有响应状态的判断:
const handleResponseStatus = (status: number): void => {
switch (status) {
case 200: // 请求成功时
// Do something...
break;
case 400: // 请求失败时
// Do something...
break;
default:
throw (new Error('No have status code!'));
}
};
刚刚的200,304等都是没有争议的状态码,但是实际开发过程中往往后台人员会自己定义一些字符串标识状态:
- 接手项目的程序员不去翻阅文档的话根本不知道这是啥玩意
- 容易造成魔鬼字符串的问题
- 用enum可以很好地解决这个问题
enum requestStatusCodes {
error = '400',
success = '200',
}
enum requestWrongCodes {
missingParameter = 'A',
wrongParameterType = 'B',
invalidToken = 'C'
}
const handleWrongStatus = (status: string): void => {
// 如果觉得 requestWrongCodes.missingParameter 太长了,也可以用以下方式:
const { missingParameter, wrongParameterType, invalidToken, } = requestWrongCodes;
switch (status) {
case missingParameter:
// Do something...
break;
case wrongParameterType:
// Do something...
break;
case invalidToken:
// Do something...
break;
default:
throw (new Error('No have wrong code!'));
}
};
- 枚举分为两种:字符串到字符串之间的映射和字符串到数字之间的映射。即key和value反向对应的对象,如下所示:
enum Language { //枚举名称为大写的单数形式
English, //枚举中的键也为大写
Spanish,
Russian
}
console.log(Language);
//ts自动推导出来的Language如下
{
'0': 'English',
'1': 'Spanish',
'2': 'Russian',
English: 0,
Spanish: 1,
Russian: 2
}
- 枚举中的值使用点号或者方括号
let myFirstLanguage = Language.English
let mySecondLanguage = Language['Spanish']
console.log(myFirstLanguage, mySecondLanguage); //0 1
- 一个枚举可以分成几次声明,ts会自动把各部分合并在一起,注意,如果分开声明枚举,ts只能推导出其中一部分的值,因此最好为枚举中的每个成员显式赋值
enum Language {
English = 0,
Spanish = 1,
}
enum Language {
Russian = 2
}
- 不必为枚举中的所有成员都赋值,ts会尽其所能推导出缺少的值:
enum Language {
English = 1,
Spanish = 100 + 1,
Russian //ts推导为102
}
console.log(Language);
- 枚举的值可以为字符串,甚至混用字符串和数字
enum Color {
Red = '#c10000',
Blue = '#007ac1',
Pink = 'oxc10050',
White = 255
}
let red = Color['Red']
let white = Color.White
console.log(red, white); //#c10000 255
- ts比较灵活,允许通过值访问枚举,也允许通过键访问枚举,不过容易导致问题
enum Language {
English,
Spanish,
Russian,
}
console.log(Language[0], Language[1]); //English Spanish
Language[‘Chinese’]和 Language[6]明明都不存在,为什么前者报错后者不报错呢?
- 利用js实现enum
- 实现key-value的反向对应的对象
- 不可修改
const newEnum = (descriptions) => {
const result = {}
Object.keys(descriptions).forEach(description => {
console.log(result[description] = descriptions[description]);//注意,等号这个会返回等于的值
result[result[description] = descriptions[description]] = description;
});
return Object.freeze(result)
}
let responseCode = newEnum({
error: 400,
success: 200
})
console.log(responseCode);
可以看到,enum本质上是生成键值对双向映射的对象,所以访问color[6]按照obj的惯性,是不会报错的,之后返回undefined
其实Color[6]不存在,但是TypeScript并不阻止你这么做。为了避免这种不安全的访问操作:
- 可以通过const enum指定使用枚举的安全子集。下面使用该方法重写前面的Language枚举
- const enum 不允许通过键反向查找,行为和常规的js对象很像
- 另外,默认不编译生成任何js代码(就像第八点生成的那个result对象),而是在用到枚举成员的地方内插对应的值,例如,把Lauguage.Spanish直接替换成1
- 使用const emun的好处,加入需要使用的enum特别多,那在执行时就会不停地使用 IIFE 产生 Object 将 Key 和 Value 绑定到 Object,会造成一些效率上的损失,也会增加内存,但是 const 并不会产生 Object ,也就不会有以上的问题。
- 就算到的 Enum 不多,判断时也需要一直从 Object 中找出对应的值,而如果是用 const 声明 Enum ,在编译成 JS 时就将声明的值直接放入判断中。
- const enum的内插行为带来的安全问题
- const enum内插值的行为在从其他人编写的TypeScript代码中导入const enum时可能导致安全问题:假如原作者在你编译TypeScript 代码之后更新了const enum,那么在运行时你使用的枚举与原作者的枚举指向的值可能不同,而TypeScript没有这么智能,无法得知这一变化。
- 使用const enum时请尽量避免内插,而且只在受自己控制的TypeScript程序中使用。不要在计划发布到NPM中的程序,或者开放给其他人使用的库中使用。
如果想为const enum生成运行时代码,在 tsconfig.json中把TSC选项preserveConstEnums设为true:
参考:
- 书籍-《typescript编程》
- 木庄的博客
更多推荐
已为社区贡献3条内容
所有评论(0)