TypeScript入门——扩展类型之枚举

人生不止有技术

共 4165字,需浏览 9分钟

 · 2021-09-12


前端猎手
 链接每一位开发者,让编程更有趣儿!
关注


📌 扩展类型——枚举

在上一篇文章中聊到了很多TS基础类型,那为什么又出现了扩展类型枚举,我们都知道任何东西都不是平白无故就出现的,都是为了解决特定的问题。枚举只是扩展类型其中之一,比如说还有类型别名接口

那么枚举是什么意思呢?

📢 枚举就是把一卡车西瓜一个一个摆在摊子上的过程。

有什么作用?

📢 枚举通常用来约束某个变量的取值范围,当然不仅仅是变量,还有函数的参数或者函数的返回值,比如说约束变量sex性别的范围,不是男就是女了,不可能是不男不女吧😂

看过我上一篇文章的小伙伴也许会回忆到当时文章中也定义了变量gender性别取值范围,当时是用字面量配合联合类型处理的

举个栗子🌰:

//通过字面量配合联合类型也能达到约束变量的目的
let gender : "男" | "女";

字面量配合联合类型也能达到约束变量的目的,那么它和枚举有什么区别呢?不用想,肯定是遇到解决不了的问题,否则整个枚举出来多此一举没意义。接下来我会详细地介绍,你可以学到:

  • 枚举出现的契机是什么
  • 它解决了什么问题

✨ 字面量类型的问题

🍍 1. 在类型约束位置会产生重复代码,可以使用类型别名解决该问题

举个栗子🌰:

我们在代码中定义一个gender变量,类型约束为或者,gender只能赋值男或者女,其它值不行,接下来有个查询用户的函数searchUsers,这个函数是根据性别进行查询用户的,如下:

//定义一个gender变量,并且约束为男或者女
let gender : "男" | "女";

//gender可以赋值为男或者女
gender = "女";
gender = "男";

//根据性别查询函数
function searchUsers(g:"男" | "女"{
    
}

从代码中可以看到变量gender约束函数参数约束产生相同代码"男" | "女",看过上一篇文章的小伙伴也许已经按捺不住了,因为上一篇文章提到过一个类型别名,它是可以解决这个问题的,如下:

//定义一个类型别名
type Gender = "男" | "女";

//定义一个gender变量,并且约束为男或者女
let gender : Gender;

//gender可以赋值为男或者女
gender = "女";
gender = "男";

//根据性别查询函数
function searchUsers(g:Gender{
    
}

所以在类型约束位置会产生重复代码,可以使用类型别名解决该问题。但是其它问题是没有办法通过类型别名来解决的

🍉 2. 逻辑含义和真实的值产生了混淆,会导致当修改真实值的时候,产生大量修改

举个栗子🌰:

//定义一个类型别名
type Gender = "男" | "女";

//定义一个gender变量,并且约束为男或者女
let gender : Gender;

//gender可以赋值为男或者女
gender = "女";
gender = "男";

//根据性别查询函数
function searchUsers(g:Gender{
    
}

上面代码中定义了类型别名Gender并且约束为或者,在后续写代码过程中,肯定会给gender赋值男或女,我们可以想象在几万行代码中大量用到gender变量进行赋值,有一天没吃药的产品经理提了个需求:性别用男女约束太俗了,显得没有档次,换个美女帅哥,如下:

//定义一个类型别名
type Gender = "帅哥" | "美女";

//定义一个gender变量,并且约束为男或者女
let gender : Gender;

//gender可以赋值为男或者女
gender = "女";
gender = "男";

//根据性别查询函数
function searchUsers(g:Gender{
    
}

换成美女帅哥后是不是要疯了,几十万行代码中大量使用了变量gender赋值为字面量,约束名一改,后面所有用到的地方都要跟着改,产生大量的修改,为什么会这样呢?根本原因是将逻辑含义和真实的值混淆在了一起,目前约束的美女和帅哥是真实的值,但不管是帅哥、美女,还是男、女都是一个含义,都表示生物学上的性别男和女,使用字面量类型的时候会导致真实的值和逻辑含义的值是对应的,但是在给变量赋值的时候只能赋值为真实的值,逻辑含义的值不变,但真实的值却变了,就产生了大量的修改,这个问题靠类型别名是没法解决的

🍇 3. 字面量类型不会进入到编译结果

字面量类型是不会参与编译,运行完成后会消失,如下:


如果我们想在TS中动态读取变量中有哪些取值并显示在页面上,是做不到的,因为TS在编译的时候已经丢失了变量约束信息。

第二个和第三个问题想要解决就需要靠枚举

🍀 枚举的 “道”

🥕 1. 如何定义一个枚举?

//枚举字段表示性别有哪些取值
enum 枚举名 {
    枚举字段1:值1,
    枚举字段2:值2,
    枚举字段3:值3,
}
//以性别为例
enum Gender {
    male = "美女",
    female = "帅哥",
}

从上述枚举定义来看,控而已发现有两个值,一个枚举字段名,另一个就是,之所以会有两个值,就是解决逻辑含义和真实的值所产生的混淆,而在枚举中将逻辑含义和真实的值分开了,左边是逻辑含义值,右边是真实的值,有了枚举之后就不再需要类型别名了,对字面量类型出现问题的代码进行修改:

//定义一个类型别名
//type Gender = "帅哥" | "美女";

//换成枚举
enum Gender {
    male = "美女",
    female = "帅哥",
}


//定义一个gender变量,并且约束为男或者女
let gender : Gender;

//gender可以赋值为男或者女
//gender = "女";
//gender = "男";

//使用了枚举之后,就不能用真实的值进行赋值了
gender = Gender.male;
gender = Gender.female;

//根据性别查询函数
function searchUsers(g:Gender{
    
}

如此就解决了字面量类型中第二个问题:逻辑含义和真实的值产生的混淆,一旦修改真实的值,造成后续大量代码的修改。使用了枚举之后将来直接修改真实的值就可以了,仅需要改一个地方即可,因为后续所有的代码都是用的是逻辑含义的值,这是不会变化的。

枚举另外一个好处就是,枚举会参与代码的编译,它会出现编译的结果中,枚举在JS中表现为对象,如下:

由于TS中使用了中文,所以它会进行unicode编码,编译后的JS文件中,首先声明了一个变量Gender,然后将Gender传入函数,如果Gender没有值,那么赋值为一个对象,随后给对象中添加一条属性male,赋值为美女,以及female赋值为帅哥,因此可以发现枚举是会参与代码的编译,所以我们能在代码编译运行阶段动态的打印枚举中的属性值。如下:

然而之前的类型别名是做不到的,因为类型别名在编译的时候会消失,而枚举则不会。

因此如果我们需要在运行的过程中使用某个取值范围的话,应该使用枚举,而且防止未来修改大量的代码,应当将逻辑含义跟真实的值分开,也应当使用枚举

📢 紧急通知: 翠花小姐姐来了

翠花小姐姐提了一个问题:那我们该何时用类型别名?有何时用枚举呢?

👉 解答:

实际上不用纠结,只要是取值范围都可以用枚举,用它准没错😁

🍄 2. 枚举的规则

  • 枚举的值可以是字符串或数字

    字符串刚刚已经说过了,枚举性别用的就是字符串,我们把值为数字的称为数字枚举

  • 数字枚举的值会自动自增,只有数字有这个特点

    举个栗子🌰:

    定义了一个data枚举,是周一到星期天的字段值,当给Monday赋值为1时,其它值会根据上一个值依次自增,如果第一个值没有赋值,那么它会从0开始,

  • 数字枚举的编译结果和字符串枚举编译的结果有差异

    这是数字枚举编译后的结果

🌽 3. 枚举的最佳实践

  • 尽量不要在一个枚举中既出现字符串字段,又出现数字字段
  • 使用枚举时,尽量使用枚举字段的名称,而不使用真实的值,就是把逻辑的值和真实的值分开
  • 能用枚举就用枚举,使用类型别名,那两个问题逃不掉


浏览 20
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报