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

TypeScript学习笔记——TS类型-进阶用法与实用优缺点

时间:2023-03-27 00:55:21 JavaScript

这两年无论是在社区还是在各种文章中,都有很多人在讨论Typescript。总体来说,正面信息大于负面,本文将梳理一下我对Typescript的了解。Typescript类型Typescript有哪些类型?1、Typescript基本类型,即可以直接使用的单一类型。NumberstringBoolean类型nullundefinedanyunknownvoidobject枚举never2,复合类型,包括单一类型的多种类型。数组类型元组类型字面量类型接口类型3.一个类型不能满足要求怎么办?可空类型,任何类型都可以默认赋值为null或undefined。联合类型,不确定是哪种类型,但可以提供几种选择,例如:type1|类型2。交集类型必须满足多种类型的组合,如:type1&type2。在哪里使用类型?在变量中使用时在变量中使用时,直接在变量后面加上类型即可。让a:数字;让b:字符串;让c:null;让d:未定义;让e:布尔值;让obj:Ixxx={a:1,b:2,};让fun:Iyyy=()=>{};在接口中使用在接口中使用也比较简单,可以理解为多个单一类型的组合。接口IData{名称:字符串;年龄:数字;func:(s:string)=>void;}在函数中使用在函数中使用类型时,主要用于处理函数参数和函数返回值。//函数参数functiona(all:string){}//函数返回值functiona(a:string):string{}//可选参数functiona(a:number,b?:number){}Typescript高级用法Typescript中的基本用法非常简单,有js基础的同学可以很快上手。下面我们来分析一下Typescript中更高级的用法,完成更复杂的类型检查。类中的高级用法类中的高级用法主要有以下几点:继承内存getsetreadonly修饰符dfpublic、private、protected修饰符abstractclassabstract继承和存储与ES6中的函数一致,这里就不多说了,主要说说类修饰符和抽象类。类中的修饰符是体现面向对象封装的主要手段。类中的属性和方法被不同的修饰符修饰后,具有不同的权限。例如:public表示在当前类、子类、实例中是可以访问的。protected表示只能在当前类和子类中访问。private表示只能在当前类访问。classAnimal{//public、private、protected修饰符protectedAnimalName:string;只读年龄:数字;静态类型:字符串;私人年龄:数字;//属性存储getage():number{returnthis._age;}setage(age:number){this._age=age;}run(){console.log("run",this.AnimalName,this.age);}constructor(theName:string){this.AnimalName=theName;}}Animal.type="2";//静态属性constdog=newAnimal("dog");dog.age=2;//给只读属性赋值会报错dog.AnimalName;//访问在实例中受保护Errordog.run;//类中的普通继承也很简单,语法和ES6一样。Cat类扩展动物{dump(){console.log(this.AnimalName);}}letcat=newCat("catname");cat.AnimalName;//受保护的对象,错误cat.run;//正常cat.age=2;//通常在面向对象中,有一个比较重要的概念就是抽象类,抽象类用于类的抽象,可以定义一些类的公共属性和公共方法,让继承的子类去实现他们,你也可以自己实现。抽象类有以下两个特点:抽象类不能直接实例化抽象类中的抽象属性和方法,必须由子类来实现。.在ts中使用extends继承一个抽象类。使用ts中的implements来实现一个接口。接口只能用于方法声明,抽象类可以用于方法声明和方法实现。抽象类是有规律的,提取出来的是一个类的public部分,而接口只是对相同的属性和方法的抽象,属性和方法之间可以没有关系。抽象类的用法如下:abstractclassAnimal{abstractmakeSound():void;//直接定义方法实例move():void{console.log("roamingtheearch...");}}classCatextendsAnimal{makeSound(){}//必须实现的抽象方法move(){console.log('move');}}新的Cat3();接口中的高级用法接口中的高级用法主要有以下几点:继承canOptionalattributeread-onlyattributeindextype:stringandnumberfunctiontypeinterface给类添加类型。除了定义常规属性外,还可以在构造函数类型接口中定义可选属性和索引类型。接口Ia{a:字符串;b?:字符串;//可选属性readonlyc:number;//只读属性[key:number]:string;//索引类型}//接口继承interfaceIbextendsIa{age:number;}lettest1:Ia={a:"",c:2,age:1,};test1.c=2;//错误,只读属性constitem0=test1[0];//索引类型该接口还支持定义函数类型和构造函数类型。//接口定义函数类型interfaceSearchFunc{(source:string,subString:string):boolean;}letmySearch:SearchFunc=function(x:string,y:string){returnfalse;};//把类写在interfaceConstructortypecheckinginterfaceIClass{new(hour:number,minute:number);}lettest2:IClass=class{constructor(x:number,y:number){}};函数中的高级用法函数重载函数重载加载是指一个函数可以根据不同的输入参数来匹配对应的类型。例如:案例中的doSomeThing在传递一个参数时提示为数字类型。如果传递两个参数,第一个参数必须是字符串类型。//函数重载functiondoSomeThing(x:string,y:number):string;functiondoSomeThing(x:number):string;functiondoSomeThing(x):any{}letresult=doSomeThing(0);letresult1=doSomeThing("",2);我们都知道Javascript中的这种类型只有在运行时才能进行判断,所以Typescript很难进行静态判断。Typescript为我们提供了手动绑定this类型允许我们在指定this时给出静态类型提示。其实Javascript中this只有五种情况:对象调用、指向被调用对象全局函数调用、指向window对象调用apply调用、指向绑定对象dom.addEventListener调用、指向dom中的this箭头函数,绑定时指向上下文//全局函数调用-windowfunctiondoSomeThing(){returnthis;}constresult2=doSomeThing();//对象调用-对象接口IObj{age:number;//手动指定这个类型doSomeThing(this:IObj):IObj;doSomeThing2():Function;}constobj:IObj={age:12,doSomeThing:function(){returnthis;},doSomeThing2:()=>{console.log(this);},};constresult3=obj.doSomeThing();让globalDoSomeThing=obj.doSomeThing;globalDoSomeThing();//这样会报错,因为我们只允许在对象中调用//调用apply绑定对应的对象functionfn(){console.log(this);}fn.bind(document)();//dom.addEventListenerdocument.body.addEventListener("click",function(){console.log(this);//body});generic泛型代表一种类型,在定义的时候是不确定的,需要在调用的时候确定。主要包括以下知识点:泛型函数泛型类泛型约束TextendsXXX试想一下,如果一个函数直接输出传入的参数,我们要怎么写它的类型呢?传入的参数可以是任何类型,是否需要每个类型都写?要使用函数重载,你必须写每个类型,这是不合适的。对于泛型,使用一个类型占位符T来代替,使用时指定对应的类型。//使用泛型函数doSomeThing(param:T):T{returnparam;}lety=doSomeThing(1);//泛型类classMyClass{log(msg:T){returnmsg;}}letmy=newMyClass();my.log("");//泛型约束可以指定哪些类型只能在最终执行函数中使用d2(param:T):T{returnparam;}letz=d2(true);其实泛型很简单,但是很多初学Typescript的同学觉得泛型比较难,其实是因为泛型可以结合索引查询符号keyof,索引AccessorsT[k]等使得代码难读,让我们来看看。//下面四个方法表达的意思是一样的。都是取出对象中某个属性的值,组成一个数组functionshowKey1(items:K[],obj:T):T[K][]{returnitems.map((item)=>obj[item]);}functionshowKey2(items:K[],obj:T):Array{返回项目。map((item)=>obj[item]);}函数showKey3(items:K[],obj:{[KinkeyofT]:any}):T[K][]{returnitems.map((item)=>obj[item]);}functionshowKey4(items:K[],obj:{[KinkeyofT]:any}):Array{返回项目。map((item)=>obj[item]);}letobj22=showKey4<"age",{name:string;age:number}>(["age"],{name:"yhl",age:12,});高级类型Typescript中的高级类型包括:intersectiontype,uniontype,literaltype,indextype,mappingtype等.,这里主要讨论jointtypemappingtypejointtypejointtype是指一个对象可能是多种类型之一,比如:leta:number|string表示a要么是数字类型,要么是字符串类型。那么问题来了,我们如何判断运行时是什么类型呢?答案是类型守卫。类型保护是针对联合类型的,可以让我们通过逻辑判断来判断最终的类型来自哪个类型的联合类型。判断联合类型的方式有很多种:typeofinstanceofin字面量保护、===、!===、==、!=自定义类型保护,通过判断是否存在某个属性等//自定义类型保护函数isFish(宠物:鱼|鸟):宠物是鱼{return(pet).swim!==undefined;}if(isFish(pet)){pet.swim();}else{pet.fly();}mappingtype映射类型是指可以操作某种类型产生另一种符合我们要求的类型:ReadOnly,将T中的所有类型都变成只读。部分,使T中的所有类型都是可选的。Exclude,从T中排除可以赋给U的类型。Extract,提取T中可以赋给U的类型。NonNullable,从T中去掉null和undefined。ReturnType,得到函数的返回值类型。InstanceType,获取构造函数类型的实例类型。我们还可以编写自定义映射类型。//定义toPromise映射类型ToPromise={[KinkeyofT]:Promise};typeNumberList=[number,number];typePromiseCoordinate=ToPromise;//[Promise,Promise]TypescriptTypescript优点总结1.静态类型检查,及早发现问题。2.类型为文档,易于理解和协作。3.类型推导,自动补全,提高开发效率。4.出现错误时,可以大概率排除问题类型,缩短bug解决时间。实战中的优势:1.发现es规范中的deprecated方法,如:Date.toGMTString。2、避免一些不友好的开发代码,如:动态给obj添加属性。3.Vue使用变量。如果没有在data中定义,会直接抛出问题。Typescript的缺点1.开发成本的短期增加。2.有些库还没有写types文件。3.不是一个完整的超集。实战中遇到的问题:1.还有一些坑,不好解决。axios写拦截器后,typescript不能在response中体现。Typescript学习对于Typescript的入门学习,我在学习的时候看了阿里写的Typescript学习指南。分为16类讲解Typescript,包括文中提到的内容。非常适合想详细研究ts或者想查漏补缺的同学。由于篇幅原因,Typescript学习指导文档的内容就不一一列举了。完整版【直接点击获取】,一起走进TS的世界。最后,如果你正在从事一个大型项目,打字稿对你来说应该是利大于弊的。可以学!也方便理解静态类型语言是如何工作的,看到别人的Java代码其实也能有看得懂的部分。当然,你要学会根据自己的需求和项目规模合理选择工具。如果你的应用是一个简单的展示页面,添加一些UI状态的变化,就没有必要使用它。