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

为什么要使用TypeScript?代码详解ts对我们的好处

时间:2023-03-26 22:31:08 JavaScript

经过这么多年的发展,Typescript已经打败了所有的竞争对手,成为事实上的Javascript类型标准,被大量公司采用,但是还是有人问我为什么用ts?使用ts能给我们带来什么好处?这次我们通过一些实际的例子来展示使用ts的好处。1.对大多数人常犯的拼写错误提供良好的拼写检查和智能提示。然而,在js这样的动态语言中,排查错别字可能会很痛苦:constuser={name:'NicholasZhaosi',pet:{name:'Dog'}}user.name.spit('·')我想将用户名拆分为名字和姓氏。本来需要用split的方式,不小心拼成了spit。不过这种还好,引擎一运行就报错,告诉我吐不是函数。下面的错误很难发现:constuser={name:'NicholasZhaoSi',pet:{name:'Dog'},occupation:'security'}console.log(user.occupation)userhas一个属性occupation,occupation这个词本来应该是occupation,但是我们的朋友不小心拼错了occupation,多了一个c。每个人都会犯错,没关系。但是其他使用它的朋友并不知道这个词拼错了。如果按照正常职业调用,只会返回undefined。而且可能是因为我们对防空值做了一些处理,比较难发现这种错误。即使找到了,我们仍然面临一个问题。修改这个词可能需要很大的成本。稍后我们将解释重命名的成本。ts能解决以上问题吗?我们试试typeUser={name:string,pet:{name:string},occupation:string,}constuser:User={name:'NicholasZhaoSi',pet:{name:'狗子'},occupation:'security'}user.name.spit('·')//属性“spit”在类型“string”上不存在。您指的是“split”吗?console.log('Hisjobis',user.occupcation)//属性“occupcation”在类型“IUser”上不存在。您指的是“occupation”吗?当你使用ts编译功能,或者安装ts相关的lint时,很容易出现如上提示。帮助我们排查开发阶段相应的错误。同时我们也可以通过ts来限制变量或者参数的类型,避免js默认隐式转换带来的一些麻烦。也许你见过一些面试题,比如下面的js:""==0;[]==0;[]==![];[]==![1,2,3];所有比较表达式的计算结果为真。js有一个比较复杂的隐式转换规则,具体可以参考这篇总结解释javascript中的比较//在js中,0,-0,null,false,NaN,undefined,oranemptystring"",inthecomparison所有操作都认为是false""==0;//true//比较的一端是number,那么另一端执行toPrimitive(value)//array的toPrimitive返回它的toString//[]的toString()isAnemptystring//比较的一端是字符串,另一端是数字,则将字符串转为Number类型//空字符串会转为0Number('')==0[]==0;//true//先执行![],上面提到false的情况,[]作为数组对象为true,取反后为false,当比较的两端之一为boolean时,bool值转换为数字,false为0,true为1,然后变回上一题,重复上一题的操作[]==![];//true[]==![1,2,3];//真[0]==![0]//true建议大家在生产环境中尽量不要使用这些复杂的转换特性,以防写错或者记错造成bug。比较判断的意思要尽量明确,比如[].length==0或者![].length,简洁易懂。或者在写法中使用三重等号[].length===0,三重等号会先校验等号两边的类型,类型不同则直接返回false。隐式转换也会在代码中造成一些隐患:functionincTen(n){if(n>1){returnn+10}returnn}当给这个方法传递一个正数时,返回加10,否则返回原来的值,现在传入一个字符串“10”,会发生什么?答案是“1010”。由于在js中没有类型限制,为了防止参数传递错误,我们需要在代码中加入很多参数类型的判断。functionincTen(n){if(typeofn!=='number'){throwError('typeisnotnumber')}if(n>1){returnn+10}returnn}写类型判断语句会消耗不管时间如何,即使加了检测代码,也无法第一时间发现调用错误,必须运行时才能发现问题。因此,我们可以使用ts来限制变量或参数的类型,第一时间提示参数类型错误:functionincTen(n:number){if(n>1){returnn+10}returnn}incTen('10')//错误:“10”类型的参数不能分配给“number”类型的参数。ts为我们提供了非常有用的智能提示,同时它可以在编写或者编译阶段提示很大一部分错误,让我们修改。注意!当您将变量的类型设置为任意时,将绕过类型检查。所以我们应该谨慎使用any类型,防止typescript变成“anyscript”//Example:constnum:any='10'incTen(num)//'1010'2.方便快捷的代码重构在刚刚的例子中提到现在,在js中,即使是简单的属性重命名也可能需要很高的成本。举个简单的例子//a.jsexportconstuser={name:'NicholasZhaoSi',}//b.jsimport{user}from'./a'functioncallName(user){console.log(user.name)}callName(user)//c.jsimport{user}from'./a'functioncallName(user){console.log(user.name)}callName(user)我们在a文件中获取了一个slave接口返回的user在用户中有一个名为name的属性。在b和c文件中导入用户,并输出其名称。这个时候需求就变了。接口返回的用户没有名字,变成了realName和nickName,现在怎么修改呢?可能有人会说,全局搜索name,全部替换成nickName即可。那稍等一下,我们修改一下代码//a.jsexportconstuser={name:'NicholasZhaoSi',pet:{name:'Dog'}}//b.jsimport{user}from'./a'functioncallName(user){console.log(user.name)}functionhisPet(user){console.log('他的宠物叫:',user.pet.name)}callName(user)hisPet(user)现在是用户中的宠物,宠物也有名字。全局替换时,宠物的名字也会替换为nickName。这次出了问题,宠物的名字变成了undefined。所以很明显,在实际开发中,简单的全局替换往往是行不通的。全局搜索后,检查每个名字是否是a文件中用户的名字,然后一一替换。如果这是一个包含数百个文件的大型项目,简单的重命名将需要半天时间。下面我们看看ts是如何帮助我们解决重命名问题的。//首先我们定义一个用户类型。//a.tsexporttypeIUser={name:stringpet:{name:string}}//设置用户为User类型exportconstuser:User={name:'NicholasZhaosi',pet:{name:'狗子'}}//b.tsimport{user,IUser}from'./a'functioncallName(user:IUser){console.log(user.name)}functionhisPet(user){console.log('hePetname:',user.pet.name)}callName(user)hisPet(user)//c.tsimport{user,IUser}from'./a'functioncallName(user:IUser){console.log(user.name)}callName(user)使用vscode的重命名功能F2,输入新的名字回车。重命名结束。3.明确定义函数参数类型和函数重载axios是一个常用的前端HTTP库,它提供了多种请求方式consturl='http://www.baidu.com'//1axios.get(url)//2axios.request({url,method:'get'})}如果我在请求时这样做,会发送什么请求?consturl='http://www.baidu.com'//1axios.get(url,{url:'http://www.google.com',method:'post'})//什么是结果毛呢?自己试一下}当我们不按照作者的意愿传递参数时,方法会怎样只能取决于作者对方法的定义,是方法描述优先还是用户传递的参数描述优先。不同的作者在不同的场景下可能有不同的定义。但是在ts中我们可以定义详细的参数类型来避免这种情况的发生。输入AxiosRequestConfig={url:string;方法:方法;标题?:任何;参数?:任何;data?:any;}functionrequest(config:AxiosRequestConfig){//dorequest}typeAxiosGetConfig={headers?:any;参数?:任何;data?:any;}functionget(url:string,config:AxiosGetConfig){//doget}//也可以利用ts的高级特性减少重复定义functionget(url:string,config:Omit){//doget}很多js库都像上面这样提供了多个调用方法,或者在一个方法中提供了多个函数重载,除了上面例子中偶尔出现的混乱之外,还有也有可能是人为失误传错了参数。//示例:functionlogPeople(){if(typeofarguments[0]=='object'){console.log('name',arguments[0].name)console.log('age',arguments[0].age)}else{console.log('name',arguments[0])console.log('age',arguments[1])}}现在这个例子实现了一个简单的人的个人信息输出方法你可以通过inapeopleobjectlogPeople({name:'ZhaoSi',age:18})//printnameZhaoSiage18也可以传入个人属性给``logPeople('ZhaoSi',18)//printnameZhaoSiage18如果你理解错误的用法。会有问题logPeople({name:'赵四'},18)//printname{name:'赵四'}age18logPeople('ZhaoSi',{age:18})//printname赵四age像{age:18}这样的问题比较容易发现,在运行时就能发现,但是一些比较负责的作者会为参数提供一些默认值,方便调用者使用。functionlogPeople(){if(typeofarguments[0]=='object'){constp={adulted:true,...arguments[0],}console.log('name',p.name)控制台。log('age',p.age)console.log('adulted',p.adulted)}else{console.log('name',arguments[0])console.log('age',arguments[1])console.log('adulted',arguments[2].adulted||true)}}上面的方法提供了一个默认值,不管是不是成人,默认为true。这样可以让方法即使写错了也能正常运行,输出也正常。只有遇到一些特殊情况或者边界值的时候才会出错。如果我们的测试用例覆盖不够全面,就会导致这类错误很难发现,导致生产环境出现一些不可预知的错误。logPeople({name:'赵四',age:18},true)提供了一种在ts中定义函数重载的方法,可以帮助我们避免这种错误。functionlogPeople(people:{name:string,age:number,adulted?:boolean}):void;functionlogPeople(name:string,age:number,adulted?:boolean):void;functionlogPeople():void{if(typeofarguments[0]=='object'){constp={adulted:true,...arguments[0],}console.log('name',p.name)console.log('age',p.age)console.log('adulted',p.adulted)}else{console.log(2)console.log('name',arguments[0])console.log('age',arguments[1])console.log('adulted',arguments[2].adulted??true)}}logPeople({name:'zhaosi',age:18,})3.ts很像对c#和java来说,这个理由看起来很可笑,其实是一个巨大的优势。ts的带头人是一个topboss,AndersHelsberg,微软的c#就是这个boss设计的,而c#的语法是从java而来的,所以ts和c#,java使用起来很像,方便了java和c#程序员使用ts参与项目的开发。比如c#,在游戏领域,unity3D是目前市场占有率最高的游戏引擎,unity3D以c#为主要语言。随着Web端3D渲染的日趋成熟,大量相关从业者加入到Web端3D渲染的开发中。使用ts可以有效减轻他们重新学习一门新语言的负担。比如egret引擎就使用ts作为默认的开发语言。开发者可以像写c#一样使用ts。几乎没有额外的学习成本。以上就是本次总结中使用ts所能带来的好处。