TypeScript中使用Enum会有什么问题,如何处理
Admin 2022-06-15 群英技术资讯 333 次浏览
但是今天有一个类型需要着重讨论下,这就是enum。
对于很多的静态语言来说,枚举是一个很非常常见的语言特性。比如,c,c#,java和swift。枚举就是你在代码里可以用的一组常量。
我们用TypeScript来新建一个enum来代表一周的几天:
enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
这个枚举使用enum关键字声明,后面跟着DayOfWeek名称。然后我们定义枚举里可以使用的常量。
现在我们定义一个方法,接受这个枚举类型的参数,来判断传入的参数是不是周末。
function isItTheWeekend(day: DayOfWeek) { switch (day) { case DayOfWeek.Sunday: case DayOfWeek.Saturday: return true; default: return false; } }
最后,我们可以这要用:
console.log(isItTheWeekend(DayOfWeek.Monday)); // log: false
对于消除程序里的魔法字符串来说,这是一个非常有用的方法。
但是,事情远不是我们想的这么简单。下面的代码调用会在TypeScript编译之后得到什么呢?
console.log(isItTheWeekend(2)); // is this valid?
知道结果你会吓一跳。这样的调用是符合TypeScript规则的,编译器也会顺利编译。
上面的情况可能会让你认为你发现了一个TypeScript的bug。其实TypeScript就是这么设计的。
我们这里新建了一个数字枚举,而且我们可以在TypeScript Playground里看看编译出来的结果是什么:
var DayOfWeek; (function (DayOfWeek) { DayOfWeek[DayOfWeek["Sunday"] = 0] = "Sunday"; DayOfWeek[DayOfWeek["Monday"] = 1] = "Monday"; DayOfWeek[DayOfWeek["Tuesday"] = 2] = "Tuesday"; DayOfWeek[DayOfWeek["Wednesday"] = 3] = "Wednesday"; DayOfWeek[DayOfWeek["Thursday"] = 4] = "Thursday"; DayOfWeek[DayOfWeek["Friday"] = 5] = "Friday"; DayOfWeek[DayOfWeek["Saturday"] = 6] = "Saturday"; })(DayOfWeek || (DayOfWeek = {}));
运行结果是:
事实上枚举就是一个JavaScript对象。
这个对象的属性就是根据我进定义的枚举常量生成,还根据定义的顺序生成了对应的数字(顺序,Sunday是0,Saturday是6)。这个对象也有数字作为key,对应的常量字符串作为值的属性。
因此,我们可以给上面的方法传入数字,数字映射到对应的枚举值。枚举既是一个数字常量也是一个字符串常量。
如果一个方法接收一个枚举类型参数,但是一个任意的数字就可以通过编译的话。这样的结果显然破坏了TypeScript构建的类型安全体系。这什么时候可以用呢?
假设你有一个服务返回一个JSON串,你想把这个串建模,对应的某个属性是一个枚举。
在你的数据库里存的是数字。定义一个TypeScript枚举可以很容易解决这个问题:
const day: DayOfWeek = 3;
这个在赋值时执行的显示的类型转换会把数字转换成枚举的对应常量。也就是说我们在代码里使用这个枚举会让代码更容易读懂。
枚举的成员对应的数字是根据枚举常量定义的顺序生成的。那我们是否可以控制这个数字的值呢?是可以的。
enum FileState { Read = 1, Write = 2 }
只是描述一个文件可能的状态的枚举。
它可能是读也可能是写状态,我们显示的定义了枚举值。现在就很明确什么样的值是合理的,因为显示定义了。
但是还有另一个情况很有用,位值(Bit)。
我们再来看一下这个FileState枚举,给它添加一个新的枚举值ReadWrite:
enum FileState { Read = 1, Write = 2, ReadWrite = 3 }
之后假设有一个方法接受这个类型的参数:
const file = await getFile("/path/to/file", FileState.Read | FileState.Write);
我们在FileState上使用了|操作符。这样我们可以使用位运算来获得一个新的枚举值。在这个例子里面就是3,ReadWrite的值。
事实上,我们可以写的更清楚一些:
enum FileState { Read = 1, Write = 2, ReadWrite = Read | Write }
这个ReadWrite的值不是写死的,而是位运算得到的。
但是再这样使用枚举的时候要多加小心。
如下的枚举:
enum Foo { A = 1, B = 2, C = 3, D = 4, E = 5 }
如果要得到E(或者5),可以位运算得到么:Foo.A | Foo.D or Foo.B | Foo.C?
所以如果要用枚举值做位运算,那么明确如何得到这个值。
一般情况下,每个枚举值都会有一个默认的数字值。如果需要也可以明确的给这些枚举值赋值。另外,还可以给某部分枚举赋值:
enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday = 10, Thursday, Friday, Saturday }
前几个值是按照位置赋值,Sunday到TuesDay是0到2.之后在Wednesday给了一个新值,从这开始每个值都递增1. 这就可能会出现问题了:
enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday = 10, Thursday = 2, Friday, Saturday }
Tuesday赋值为2,生成的JavaScript是什么样子呢:
var DayOfWeek; (function (DayOfWeek) { DayOfWeek[DayOfWeek["Sunday"] = 0] = "Sunday"; DayOfWeek[DayOfWeek["Monday"] = 1] = "Monday"; DayOfWeek[DayOfWeek["Tuesday"] = 2] = "Tuesday"; DayOfWeek[DayOfWeek["Wednesday"] = 10] = "Wednesday"; DayOfWeek[DayOfWeek["Thursday"] = 2] = "Thursday"; DayOfWeek[DayOfWeek["Friday"] = 3] = "Friday"; DayOfWeek[DayOfWeek["Saturday"] = 4] = "Saturday"; })(DayOfWeek || (DayOfWeek = {}));
看起来Tuesday和Thursday的数值都是2。
所以,需要显示的设定数值。
目前为止,我们只讨论了数值枚举,但是枚举的值不一定非的是数字。它也可以是任何常量或者计算值:
enum DayOfWeek { Sunday = "Sun", Monday = "Mon", Tuesday = "Tues", Wednesday = "Wed", Thursday = "Thurs", Friday = "Fri", Saturday = "Sat" }
现在就不能给isItTheWeekend方法穿数字参数了。这个枚举已经不再是数字枚举。然而,我们也不能传任意字符串进去,因为枚举知道什么样的值才是合理的。
这样也带来另外一个问题:
const day: DayOfWeek = "Mon";
这样是行不通的。
字符串并不能直接给枚举赋值,而是需要一个显示的类型转换:
const day = "Mon" as DayOfWeek;
能不能给它赋其他值呢?事实上枚举可以有很多类型的值:
enum Confusing { A, B = 1, C = 1 << 8, D = 1 + 2, E = "Hello World".length }
这个例子的枚举值都是数字。但是这些数字值可以直接赋值,也可以是计算值,或者是字符串的length属性。如果都是常量的话,那么就可以是多种类型的值:
enum MoreConfusion { A, B = 2, C = "C" }
这种情况就很难让人理解枚举后面的数据是怎么工作的。所以,最好不要用这样的枚举。
TypeScript的枚举是对JavaScript的一个很好地补充,使用得当将非常有用。它将有助于清理代码中存在的魔术值(magic values)字符串、数字。而且它是类型安全的。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇我们来了解关于JS内存泄漏的相关内容,对于JS内存泄漏以及其影响有很多朋友是不知道,JS内存泄漏对我们正常的程序运行是有很大影响的,对此下文就给大家来解决JS内存泄漏和如何防止内存泄漏。
JavaScript属性操作,下文有实例供大家参考,对大家了解操作过程或相关知识有一定的帮助,而且实用性强,希望这篇文章能帮助大家,下面我们一起来了解看看吧。
微信小程序中的下拉框怎样做?在实际的项目中,我们常会遇到实现下拉框效果的需求,今天我们就来了解一下怎样做一个简单的小程序中的select下拉框,这里使用到的是transform过渡,实现效果及代码如下。
本篇文章给大家带来了关于JavaScript的相关知识,其中主要整理了日期对象Date的相关问题,包括了Date对象的创建、Date对象的方法等等内容,下面一起来看一下,希望对大家有帮助。
这篇文章主要介绍了react中的props 的使用及进行限制的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008