介绍
在昨天的文章中,我们介绍了如何使用typescript
中的枚举类型Enum
来处理状态值。今天,我们将探讨一个更好的实践:使用const
代替枚举。为什么说const
是更好的方案呢,因为typeScript中的枚举类型有一些弊端。
枚举类型的弊端
枚举类型无法实现真正的类型安全
对于数字类型的枚举,无法实现真正的类型安全,比如下面的枚举类型定义:
1 | enum JobStatus { |
这里面定义了五种类型的状态,分别用数字1到5来表示。但是这里有一个隐藏的问题,你可以将任意数字赋值给JobStatus
类型的变量,而不管这个数字是否在1到5之间。例如:
1 | let status: JobStatus = 1; // 这是合法的 |
这就导致了类型安全性的问题,枚举类型并不能限制状态值只能是1到5之间的数字。
一个更好的做法是使用字符串类型代替数字类型:
1 | const enum JobStatus { |
这样就可以确保状态值只能是枚举定义的字符串,而不能是其他任意字符串。
1 | const status: JobStatus = JobStatus.PENDING; // 这是合法的 |
枚举类型不支持Tree-Shaking
Tree-Shaking
是指在打包时去除未使用的代码。TypeScript的枚举类型在编译后会生成一个对象,这个对象包含了所有枚举成员的映射关系。即使程序中没有使用这个枚举类型,编译后的代码中仍然会保留这个对象。这会导致打包后的代码体积增大。
使用const
代替枚举
上面提到的两点问题,使用const
可以很好地解决。下面使用const
来实现同样的功能,首先定义Job状态常量,因为要兼顾后端接口的整数类型和前端显示的字符串类型,我们索性将其封装到一起。用code
表示状态值,用label
表示状态的显示名称。
1 | const JobStatus = { |
接下来定义Job接口,使用JobStatusType
来描述状态类型。
1 | interface Job { |
后端返回的数据和先前一样用数字类型来表示Job状态。
1 | const jobs = [ |
最后是打印Job的函数,这里涉及到一个问题,我们不能像之前一样直接使用字符串来访问状态的显示名称,因为现在状态是一个对象,我们需要通过状态的code
来获取对应的label
。
1 | function printJobStatus(job: Job) { |
现在我们可以调用这个函数来打印Job的状态:
1 | jobs.forEach(printJobStatus); |
这样做的好处是可以省去之前的映射函数getJobDisplayName
,因为我们在定义JobStatus时已经将状态码(code)和显示名称(label)封装在一起了。
1 | // 该函数可以省略 |
弊端是多了一个查找的过程,但这个查找过程是非常轻量级的,因为我们只需要遍历一次JobStatus
对象来找到对应的状态。
const
代替枚举的好处在于:
- 类型安全:使用
const
可以确保状态值只能是预定义的状态,而不能是其他任意值。 - Tree-Shaking:
const
支持Tree-Shaking,只有实际使用才会被保留,从而减小打包后的代码体积。
好了,今天就到这里了,我们明天见。