在写ts相关代码的过程中,总能看到接口和类型。它们的功能好像都差不多,同一个功能随便一个都可以实现,而且都是很好用的,难得真正了解它们的区别,具体用在什么场景下,自己学习内容记录分享类型别名type首先,什么是类型别名?类型别名用于为类型赋予新名称。使用type创建类型别名。类型别名不仅可以用来表示基本类型,还可以用来表示对象类型、联合类型、元组和交集。让我们看一些例子:typeuserName=string;//原始类型typeuserId=string|数字;//联合类型arr=number[];//对象类型typePerson={id:userId;//可以使用Typename:userName;age:number;gender:string;isWebDev:boolean;};//generictypeTree={value:T};constuser:Person={id:"901",name:"tsubaki",age:22,gender:"female",isWebDev:false,};常量数字:arr=[1,8,9];接口接口是另一种命名数据结构(例如对象)的方式;与类型不同,接口仅限于描述对象类型。接口的声明语法也不同于类型别名。让我们将上面的类型别名Person重写为接口声明:之前,我们先看看两者的相同点(开发时为什么用同一个)Object和Function都可以用来描述对象或函数,只是语法不同:TypetypePoint={x:number;y:number;};typeSetPoint=(x:number,y:number)=>void;InterfaceinterfacePoint{x:number;y:number;}interfaceSetPoint{(x:number,y:number):void;}两者都可以被继承。接口和类型都可以被继承。另一件值得注意的事情是接口和类型别名并不相互排斥。类型别名可以从接口继承,反之亦然。只是在实现形式上,略有区别_前端培训。interface继承interfacePerson{name:string}interfaceStudentextendsPerson{stuNo:number}interface继承typetypePerson{name:string}interfaceStudentextendsPerson{stuNo:number}type继承typetypePerson{name:string}typeStudent=Person&{stuNo:number}typeinheritsinterfaceinterfacePerson{name:string}typeStudent=Person&{stuNo:number}implements类可以实现接口和类型(联合类型除外)interfaceICat{setName(name:string):void;}classCatimplementsICat{setName(name:string):void{//todo}}//typetypeICat={setName(name:string):void;}classCatimplementsICat{setName(name:string):void{//todo}}上面说的特例,类不能实现union类型,什么意思呢?类型Person={名称:字符串;}|{setName(name:string):void};//无法实现联合类型Person//错误:一个类只能实现一个对象类型或对象类型与静态已知成员的交集.classStudentimplementsPerson{name="张san";setName(name:string):void{//todo}}上面我们说了接口和类型的相同点,接下来我们来看看它们的不同点。两者的区别1.定义基本类型别名type可以定义基本类型别名,但是不能定义接口,如:typeuserName=stringtypestuNo=number...2.声明联合类型type可以声明联合类型,例如:typeStudent={stuNo:number}|{classId:number}3.声明元组类型声明元组类型:typeData=[number,string];以上这些都可以按类型来做,但是不能按接口来做,接下来说说什么类型不能做4.声明合并如果多次声明一个同名接口,TypeScript会将它们合并为一个声明并处理它们作为一个界面。这称为语句合并,例如:interfacePerson{name:string}interfacePerson{age:number}letuser:Person={name:"Tolu",age:0,};这种情况下,如果是type,重复使用Person会报错:typePerson{name:string};//Error:Theidentifier"Person"isrepeated.ts(2300)typePerson{age:number}5.Indexsignatureproblem如果你经常使用TypeScript,你一定遇到过类似的错误:Type'xxx'isnotassignabletotype'yyy'Indexsignatureismissingintype'xxx'。看一个例子来理解问题:interfacepropType{[key:string]:string}letprops:propTypetypedataType={title:string}interfacedataType1{title:string}constdata:dataType={title:"Orderpage"}constdata1:dataType1={title:"OrderPage"}props=data//错误:类型'dataType1'不可分配给类型'propType';indexsignatureismissingintype'dataType1'props=data1我们发现dataType和dataType1对应的类型相同,但是接口定义赋值失败。是什么原因?一开始我很疑惑,最后在stackoverflow:上找到了一个类似的问题,幸运的找到了一个有效的答案:翻译的大概意思是:Record和{[key:string]:string}一样。仅当该类型的所有属性都是已知的并且可以根据该索引签名进行检查时,才允许将子集分配给索引签名类型。在您的情况下,从exampleType到Record的所有内容都是可分配的。这只能针对对象字面量类型进行检查,因为对象字面量类型一旦声明就无法更改。因此,索引签名是已知的。相反,当您使用接口声明变量时,它们的类型在那一刻不是最终的。由于interfac可以进行声明合并,所以总是可以在同一个interface_web前端训练定义的类型中添加新的成员。结合语句合并的解释,就很容易理解了。也就是说interface定义的类型是不确定的,后面还会有一个:interfacepropType{title:number}这样propType的类型就变了。总结一下,官方推荐使用interface,其他不能满足要求的情况使用type。但实际上,由于联合类型和交集类型非常常用,所以避免不了大量使用类型的场景,一些复杂的类型也需要组装成类型别名来使用。因此,如果你想保持代码的统一,你仍然可以选择使用类型。通过以上对比,类型别名其实可以覆盖接口的大部分场景。对于React组件中的props和state,使用type,可以保证组件使用的地方不能随意在其上添加属性。如果有自定义需求,可以通过HOC重新打包。编写第三方库时使用接口,其更灵活自动的类型合并可以应对未知复杂的使用场景。文章转载自前端开发