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

TypeScript知识笔记---进阶

时间:2023-03-28 13:53:10 HTML

二、进阶1、类型推断:如果没有明确指定类型,TypeScript会根据类型推断的规则推断出一个类型。如果定义时没有赋值,不管后续有没有赋值,都会被推断为任意类型,根本不会进行类型检查:letmyFavoriteNumber;myFavoriteNumber='七';我的最爱号码=7;表示该值可以是多种类型之一,用“|”分隔每种类型。当给一个联合类型的变量赋值时,会根据类型推断的规则推断出一个类型。让myFavoriteNumber:字符串|number;myFavoriteNumber='seven';myFavoriteNumber=7;myFavoriteNumber=true;//index.ts(2,1):错误TS2322:类型'boolean'不可分配给类型'string|数字'。3.类型别名:类型别名用于给类型起一个新的名字。使用type创建类型别名,通常用于联合类型。类型名称=字符串;类型名称解析器=()=>字符串;类型名称或解析器=名称|NameResolver;functiongetName(n:NameOrResolver):Name{if(typeofn==='string'){返回n;}else{返回n();}}当TypeScript不确定一个联合类型的变量是哪种类型时,我们只能访问该联合类型的所有类型共有的属性或方法。4.字符串字面量类型:字符串字面量类型用于约束值只能是几个字符串中的一个。我们使用type来定义一个字符串字面量类型EventNames,它只能取三个字符串之一。请注意,类型别名和字符串文字类型都是使用类型定义的。输入EventNames='点击'|'滚动'|'鼠标移动';functionhandleEvent(ele:Element,event:EventNames){//做点什么}handleEvent(document.getElementById('hello'),'scroll');//没问题handleEvent(document.getElementById('world'),'dblclick');//error,eventcannotbe'dblclick'5.接口:在面向对象语言中,接口(Interfaces)是一个非常重要的概念,它是对行为的抽象,具体如何动作需要类来实现(类)。TypeScript中的接口是一个非常灵活的概念。除了抽象类的部分行为外,它还常被用来描述“对象的形状(Shape)”。接口人{名称:字符串;age:number;}lettom:Person={name:'Tom',age:25};lettom:Person={name:'Tom'};//index.ts(6,5):错误TS2322:类型'{名称:字符串;}'不可分配给类型'Person'.lettom:Person={name:'Tom',age:25,gender:'male'};//index.ts(9,5):errorTS2322:Type'{name:string;年龄:数字;性别:字符串;}'不可分配给类型'Person'。可以看出,在赋值的时候,变量的形状必须和接口的形状保持一致。⑴可选属性:该属性是可选的,使用?标志,但仍然不允许添加未定义的属性。接口人{名称:字符串;age?:number;}lettom:Person={name:'Tom'};lettom:Person={name:'Tom',age:25,gender:'male'};//报错,是仍然不允许添加未定义的属性⑵任意属性:使用[propName:string]定义任意属性取值字符串类型。一旦定义了任何属性,确定属性和可选属性的类型都必须是其类型的子集。接口人{名称:字符串;年龄?:数字;[道具名称:字符串]:字符串;//更改为[propName:string]:any;没错//也可以改成联合类型[propName:string]:string|number;}lettom:Person={name:'Tom',age:25,gender:'male'};//任意属性的值允许为字符串,但可选属性age的值为number,不是字符串⑶只读属性:可以使用readonly定义只读属性。接口人{只读id:数字;名称:字符串;年龄?:数字;[propName:string]:any;}lettom:Person={id:89757,name:'Tom',gender:'male'};tom.id=9527;//index.ts(14,5):errorTS2540:无法分配给“id”,因为它是常量或只读属性。6。类:(1)publicprivateandprotected:TypeScript可以使用三种访问修饰符(AccessModifiers),分别是public、private和protected。public修饰的属性或方法是公开的,可以在任何地方访问。默认情况下,所有属性和方法都是公共的。private修饰的属性或方法是私有的,不能在声明它的类之外访问。protected修饰的属性或方法是protected,它类似于private,不同的是它也允许在子类中访问。注意:①用private修饰的属性或方法不能直接访问,子类中也不允许访问;如果用protected修饰,则允许在子类中访问。需要注意的是,在TypeScript编译的代码中,私有属性的外部访问是不受限制的。动物类{公共名称;私有类型;公共构造函数(名称,类型){this.name=name;this.type=类型;}}leta=newAnimal('Jack','human');console.log(a.name);//Jacka.name='Tom';console.log(a.name);//Toma.type='monkey';console.log(a.type);//index.ts(9,13):errorTS2341:Property'type'isprivateandonlyaccessiblewithinclass'Animal'。②当构造函数被修改为private时,该类不允许被继承或实例化;当构造函数被修改为protected时,该类只允许被继承。⑵参数属性和readonly:构造函数参数中也可以使用修饰符和readonly,相当于在类中定义了属性,并为属性赋值,使代码更加简洁。readonly属性关键字readonly只允许出现在属性声明或索引签名或构造函数中。注意,如果readonly等访问修饰符同时存在,则需要写在其后。类动物{//公共名称:字符串;publicconstructor(publicname){//publicconstructor(publicreadonlyname){//this.name=name;}}classAnimal{只读名称;公共构造函数(名称){这个.name=名称;}}leta=newAnimal('Jack');console.log(a.name);//Jacka.name='Tom';//index.ts(10,3):TS2540:Cannotassignto'name'becauseitisaread-onlyproperty.⑶Abstractclass:abstract用于定义抽象类和其中的抽象方法。首先,抽象类是不允许实例化的,其次,抽象类中的抽象方法必须由子类来实现。即使是抽象方法,TypeScript编译结果中仍然会存在这个类。抽象类Animal{公共名称;公共构造函数(名称){this.name=name;}publicabstractsayHi();}classCatextendsAnimal{publicsayHi(){//需要实现抽象方法console.log(`Meow,Mynameis${this.name}`);}}leta=newAnimal('Jack');//无法实例化抽象类//index.ts(9,11):errorTS2511:Cannotcreateaninstanceoftheabstractclass'Animal'.letcat=newCat('Tom');//只能实例化子类⑷类的类型:给类添加TypeScript类型很简单,类似于interface:classAnimal{name:string;构造函数(名称:字符串){this.name=name;}sayHi():string{return`我的名字是${this.name}`;}}leta:Animal=newAnimal('Jack');console.log(a.sayHi());//我的名字是Jack7。类和接口:一般来说,一个类只能继承另一个类,有时不同的类可以有一些共同的特性。这时,可以将特征提取到接口中,用implements关键字实现。界面警报{警报():无效;}界面灯{lightOn():无效;lightOff():void;}classDoor{}//一个接口可以被多个类继承classSecurityDoorextendsDoorimplementsAlarm{alert(){console.log('SecurityDooralert');}}类Car实现Alarm{alert(){console.log('Caralert');}}//一个类可以继承多个接口classCarimplementsAlarm,Light{alert(){console.log('Caralert');}lightOn(){console.log('车灯亮');}lightOff(){console.log('车灯关闭');}}//接口和接口也可以继承interfaceLightableAlarmextendsAlarm{lightOn():void;lightOff():void;}注意:接口也可以继承类,但不是标准的类继承。类点{x:数字;y:数字;构造函数(x:数字,y:数字){this.x=x;这个.y=y;}}interfacePoint3dextendsPoint{z:number;}letpoint3d:Point3d={x:1,y:2,z:3};//等价于:classPoint{x:number;y:数字;构造函数(x:数字,y:数字){this.x=x;这个.y=y;}}interfacePointInstanceType{x:数字;y:number;}//相当于interfacePoint3dextendsPointInstanceTypeinterfacePoint3dextendsPoint{z:number;}letpoint3d:Point3d={x:1,y:2,z:3};当我们声明interfacePoint3dextendsPoint时,Point3d继承的其实是类Point的实例类型。也就是说,可以理解为定义了一个接口Point3d,继承了另一个接口PointInstanceType。值得注意的是,与Point相比,PointInstanceType缺少构造方法,声明Point类时创建的Point类型只包含其实例属性和实例方法。8.泛型:泛型(Generics)是指在定义函数、接口或类时不事先指定具体类型,而是在使用时指定类型的特性。简单地说,它用于指定函数、接口或类输入/输出的类型。functioncreateArray(length:number,value:T):Array{letresult:T[]=[];for(leti=0;i(3,'x');//['x','x','x']//当然也可以让类型推导自动计算出来,不用手动指定createArray(3,'x');//['x','x','x']在上面的例子中,我们在函数名后面添加了,其中T用来指代任何输入类型,它可以用在下面的输入值中:T并输出Array。(1)多类型参数:定义泛型时,可以一次定义多个类型参数:functionswap(tuple:[T,U]):[U,T]{return[tuple[1],元组[0]];}交换([7,'七']);//['seven',7]⑵泛型约束:在函数内部使用泛型变量时,由于我们事先不知道它是什么类型的变量,所以不能任意操作它的属性或方法。这时候我们可以限制泛型,只允许这个函数传入那些包含length属性的变量。这是通用约束。interfaceLengthwise{length:number;}functionloggingIdentity(arg:T):T{console.log(arg.length);returnarg;}多个类型参数也可以相互约束:functioncopyFields(target:T,source:U):T{for(letidinsource){target[id]=(来源)[id];}returntarget;}letx={a:1,b:2,c:3,d:4};copyFields(x,{b:10,d:20});//其中T需要继承U,从而保证T不会出现在U中不存在的字段。⑶通用接口:您可以使用接口来定义函数需要符合的形状。interfaceCreateArrayFunc{(length:number,value:T):Array;}letcreateArray:CreateArrayFunc;createArray=function(length:number,value:T):Array复制代码{让结果:T[]=[];for(leti=0;i{zeroValue:T;添加:(x:T,y:T)=>T;}letmyGenericNumber=newGenericNumber();myGenericNumber.zeroValue=0;myGenericNumber.add=function(x,y){returnx+y;};//泛型的默认类型functioncreateArray(length:number,value:T):Array{letresult:T[]=[];for(leti=0;i