当前位置: 首页 > Web前端 > HTML

TypeScript枚举和类型约束

时间:2023-03-28 00:54:53 HTML

●上一章讲了TS的接口●本章讲了TS的枚举和约束枚举理解枚举●枚举的概念在很多计算机语言中都有,而JS中没有枚举的概念,为了弥补这个缺点,在TS中加入了枚举类型●什么是枚举?枚举(meiju):枚举就是一个一个枚举,把所有的情况都枚举出来,那么在取值的时候,只能用这几种,其他的都不能用。计算机语言中的枚举:把所有的常量放在一个集合中,让几个常量成为一组相关内容//对于一个业务逻辑,我需要经常使用四个方向的字符串constUP='up'constRIGHT='right'constDOWN='down'constLEFT='left'●对于上面四个变量●我不关心任何逻辑,我不能限制你只能使用这四个变量中的一个//封装一个功能函数functionutil(dir){}无论用什么方法,都不能限制接收到的dir参数必须是上面列出的四个方向●这时候我们可以使用枚举●首先在TS中,使用enum关键字创建一个枚举设置,把我们需要的四个常量放进去settorestrictsomedatafunctionutil(dir:Direction){}这个约定dir参数的值只能是Directione中的常量数集,不能用别的。只要写了Direction以外的东西,枚举里面的内容就无法用数字枚举出来。数值枚举示例:枚举类型中的每个常量都是一个数字●在TS中,枚举中的每个常量,当你不设置值时,默认为数字类型enumPages{ONE,//0TWO,//1THREE//2}●你在枚举中的常量,第一个默认值为0,后面的都会增加+1。此时Pages.ONE=>0Pages.TWO=>1Pages.THREE=>2●我们也可以指定值enumPages{ONE=10,//10TWO=20,//20THREE=30//30}●此时枚举中的常量setare我们指定好的值●我们也可以指定部分值enumPages{ONE=10,//10TWO,//11THREE//12}●指定常量之后未指定的常量会按照+1的规则enumPages{ONE,//0TWO=10,//10THREE//11}enumPages{ONE,//0TWO=10,//10THREE,//11FOUR=30,//30FIVE//31}字符串枚举●字符串枚举:枚举集中每个常量的值都是字符串类型●在TS中,必须在字符串类型之前指定一个值enumDirection{UP='up',RIGHT='right',DOWN='down',LEFT='left'}●在TS中,枚举常量与任何东西都不相同,包括原始字符串functionutil(dir:Direction){}●这是因为,在TS中,每个常量在枚举中是一个唯一值●所以当你使用枚举来限制一个数据时,你只能使用枚举中的值●这也避免了你因手写错误而导致的单词错误。例如,你认为“form”和“from”是同一个词吗?异构枚举●异构枚举:其实就是把数字枚举和字符串枚举混在一起了●但是你可能不会这样用,因为作为数据的集合,我们一般不会把数字和字符串混在一起使用enumInfo{ONE,UP='up',TWO=2,LEFT='left'}●有一个需要注意的是,在枚举集中,当你不给某个key设置值的时候,它会默认按照前一个的值+1。所以如果前一个是字符串枚举,那么下一个就必须手动赋值,否则会报错,如果上一个是数字枚举,那么下一个就不需要手动赋值了,而枚举将根据之前的+1计算合并。TS中的枚举支持合并。多个枚举类型可以分开写。会自动合并enumDirection{UP='up',RIGHT='right',DOWN='down',LEFT='left'}enumDirection{TOP='top',BOTTOM='bottom'}functionutil(dir:Direction){}util(Direction.BOTTOM)util(Direction.LEFT)●这里定义的两个枚举都叫Direction,编译的时候会自动放在一起,不会有冲突。反向映射●TS中的数字枚举,在编译时,key和value会被反向编译一次enumPages{ONE,//0TWO,//1THREE//2}●以此为例,如何实现它工作CompiledvarPages;(function(Pages){Pages[Enum["ONE"]=0]="ONE"Pages[Enum["TWO"]=1]="TWO"Pages[Enum["THREE"]=2]="THREE"})(Pages||(Pages={}));编译结果Pages={ONE:0,TWO:1,THREE:2,'0':'ONE','1':'TWO','2':'THREE'}●也就是说,我们在TS中使用的时候,如果是数字的枚举,那么我们可以通过key得到对应的数字,或者通过对应的数字对应keyenum页面{一,//0二,//1三//2}console.log(Pages.ONE)//0console.log(Pages.TWO)//1console.log(Pages.THREE)//2console.log(Pages[0])//'ONE'console.log(Pages[1])//'TWO'console.log(Pages[2])//'THREE'常量枚举●常量枚举,在枚举之上也就是说,添加了const关键字来修改它。编译时,枚举内容会被删除,只保留编译结果。对于数字枚举,不再支持反向映射能力,只能使用key访问。非常量枚举enumPages{ONE,//0TWO,//1THREE//2}console.log(Pages.ONE)console.log(Pages.TWO)console.log(Pages.THREE)编译后的js文件常量enumerationconstenumPages{ONE,//0TWO,//1THREE//2}console.log(Pages.ONE)console.log(Pages.TWO)console.log(Pages.THREE)编译后的js文件类型约束。●在TS中,有一个很神奇的关键字,叫做type。类型,也称为类型别名,有很多神奇的功能。不仅可以支持接口定义的对象结构,还可以支持任意手写类型。●先来看一个很简单的例子letn1:number|字符串|布尔值让n2:数字|字符串|布尔值让n3:数字|都是number或者string或者boolean●写起来很麻烦●这个时候我们可以用type给它设置一个别名设置类型Info=number|字符串|booleanletn1:Infoletn2:Infoletn3:Info这样,我们的代码是不是变得更简洁了?可能有朋友觉得这个用的不多,其实type也没有函数type只有一个常用的用法●基本类型的别名typen=numberletnum:n=100○这是一个很基本的用法,typeofnumber给一个别名,叫n○以后用n来限制变量,这时候其实是用number的基本类型组合类型i=number|stringletstr:i='前锋前端'str=100○这个是组合类型,number或者string类型有个别名叫i○我们在用i限制变量的时候,变量限制为number或者string●对象类型typeUser={name:string,age:number}letperson:User={name:'千峰前端',age:10}○这个就是对象类型,和interface很像,它的使用基本相同●对象联合类型typeUser={name:string,age:number}typePerson=User&{gender:boolean}letperson:Person={name:'千峰前端',age:10,gender:true}○这个是objectunion类型,和接口的extends继承很像●Tupletypetypedata=[number,string]letinfo:data=[10,'前锋大前端']constantlimitedtypecolor='黄色'|'橙色'|'blue'functionutil(c:color){}util('yellow')○这个颜色限制为几个值,以后用到color约束一个变量的时候○这个变量只能接受这几个values,它更像是type和in而不是enuminterface的共同点可以约束对象或函数类型○interfaceinterfaceUser{name:string;age:number}interfaceFunc{(x:number):number}○typetypeUser={name:string;age:number}typeFunc=(x:number)=>number○我们看到两种定义方式略有不同,但是后面的用法基本相同。扩展类型○接口使用extends继承interfacePerson{name:stringage:number}//使用extends关键字继承自PersoninterfaceStudentextendsPerson{classRoom:number}lets:Student={name:'千峰大前端',age:10,classRoom:1}○type使用叉号(&)实现typePerson={name:stringage:number}//使用叉号(&)typeStudent=Person&{classRoom:number}lets:Student={name:'千峰大前端',age:10,classRoom:1}uniontype○interfaceuseextendsInheritancetypetypePerson={name:stringage:number}//使用extends关键字继承Person接口StudentextendsPerson{classRoom:number}lets:Student={name:'QianfengFrontend',age:10,classRoom:1}○typeusecross(&)toextendinterfaceinterfacePerson{name:stringage:number}//使用叉号(&)吨typeStudent=Person&{classRoom:number}lets:Student={name:'前锋大前端',age:10,classRoom:1}type和interface的区别interface支持自动合并多个声明,type不支持interfaceUser{name:stringage:number}interfaceUser{classRoom:string}/*realUserinterface{name:stringage:numberclassRoom:string}*/○type如果声明同名的标识符,会报错被举报ForES6modularsyntax默认导出语法○interface支持声明,而exportdefaultinterfaceUser{name:stringage:number}○type必须先声明,默认导出类型User={name:stringage:number}exportdefaultUser必须先声明,在defaultexport中,如果直接写defaultexport会报错type可以使用typeof关键字来获取某个数据类型letbox=document.querySelector('.box')typeEleType=typeofbox○这里定义了一个EleType标识符,会根据typeof关键字检测到的box类型自动限制type。它支持使用in关键字遍历映射类型。输入名称='firstName'|'姓氏'|'AKA'typenameType={[keyinnames]:string}/*realnameType{firstName:stringlastName:stringAKA:string}*/