使用Typescript的一些注意事

白癜风饮食注意事项 http://disease.39.net/bjzkbdfyy/180612/6323898.html
背景

ts用了一年了,回顾起来,也没有那么顺利。趁这两天春节假期有时间,整理了几个自己觉得需要注意的情况,复盘一下。

我上学时学过java和C#,毕业后又做了两年C#全栈开发,对于静态类型语言是有一定经验的。ts之所以能够慢慢取代js,也是因为它是静态类型语言。

但ts和java是不一样的,本质是因为它作为一个静态类型语言,要编译成弱类型语言js来执行。所以,ts只管得了编译时,却管不了运行时。下文的很多内容,都是这个特点的具体表现。

我感觉ts为了能让自己更适应js的转型,做了很多非常繁琐(或者叫灵活)的设计,我没有详细总结,但这种感觉很强烈。所以,如果你觉得ts有些地方过于繁琐时,也不要担心,这可能不是你的问题,而是它的问题。

任何美好的东西,都是应该简单的、明确的。

易混乱的类型

如果问“ts的变量有多少种类型”,你能否回答全面?ts比js类型多一些。

nevervsvoid

只需要记住一个特点:返回never的函数,都必须存在无法到达的终点,如死循环、抛出异常。

functionfn1():never{while(true){/*...*/}}functionfn2():never{thrownewError(/*...*/)}anyvsunknownany任何类型,会忽略语法检查unknown不可预知的类型,不会忽略语法检查(这就是最大区别)

constbar:any=10;any.substr(1);//OK-any会忽略所有类型检查constfoo:unknown=string;foo.substr(1);//Error:语法检查不通过报错//(fooasstring).substr(1)//OK//if(typeoffoo===string){foo.substr(1)}//OK一些“欺骗”编译器语法检查的行为

就如同你告诉编译器:“按我写的来,不要管太多,出了事儿我负责!”

编译器不给你添麻烦了,不进行语法检查了,但你一定要考虑好后果。所以,以下内容请慎用,不要无脑使用。

ts-ignore

增加

ts-ignore的注释,会忽略下一行的语法检查。

constnum1:number=num1.substr()//Error语法检查错误constnum2:number=//

ts-ignorenum2.substr()//Ok语法检查通过any

如果ts是西游记,any就是孙悟空,自由、无约束。了解西游记大部分是从孙悟空开始,了解ts可能也是从any开始用。

但西游记最后,孙悟空变成了佛。你的any也应该变成interface或者type。

类型断言as

文章一开始说过,ts只管编译时,不管运行时。as就是典型的例子,你用as告诉编译器类型,编译器就听你的。但运行时,后果自负。

functionfn(a:string

null):void{constlength=(aasstring).lengthconsole.log(length)}fn(abc)//Ok//fn(null)//Errorjs运行报错非空断言操作符!

!用于排除nullundefined,即告诉编译器:xx变量肯定不是null或undefined,你放心吧~

同理,运行时有可能出错。

//例子1functionfn(a:string

null

undefined){lets:string=s=a//Error语法检查失败s=a!//OK——如果a真的是null或者undefined,那么s也会是null或者undefined,可能会带来bug!!!}//fn(null)

//例子2typeNumGenerator=()=number;functionmyFunc(numGenerator:NumGenerator

undefined){constnum1=numGenerator();//Error语法检查失败constnum2=numGenerator!();//OK}//myFunc(undefined)//,如果真的传入undefined,也会去执行,当然会执行报错!!!

//例子3leta:numberconsole.log(a)//Error-Variablenisusedbeforebeingassigned.letb!:numberconsole.log(b)//OK-`!`表示,你会给b一个赋值,不用编译器关心可选链?.

?.遇到null或undefined就可以立即停止某些表达式的运行,并返回undefined这里只针对null和undefined,对于0false等falsely变量是不起作用的。这一点和不一样。

这个运算符,看似是获取一个属性,其实它是有条件判断的。即,它就是一个?:三元表达式的语法糖。既然它有判断逻辑,那你考虑不到位,就有可能出错。

//例子1-获取对象属性interfaceIFoo{a:number}functionfn(obj:IFoo

null

undefined):number

undefined{consta=obj?.a//?.可选链运算符//第一,如果a是IFoo类型,则打印//第二,如果a是null或者undefined,则打印undefinedconsole.log(a,a)returna//或者undefined}fn({a:})//fn(null)//fn(undefined)

//例子2-获取数组元素functiontryGetArrayElementT(arr?:T[],index:number=0){returnarr?.[index];}//编译产出://"usestrict";//functiontryGetArrayElement(arr,index=0){//returnarr===null

arr===void0?void0:arr[index];//}

//例子3-用于函数调用typeNumGenerator=()=number;functionfn(numGenerator:NumGenerator

undefined

null){constnum=numGenerator?.();console.log(num,num)//如果不是函数,则不调用,也不会报错,返回undefined}//fn(null)//fn(undefined)

对于这种语法糖,我还是比较反感的,我觉得自己写几行逻辑判断会更好。它虽然简洁,但是它会带来阅读理解上的负担,代码简洁不一定就可读性好——当然了,如果大家都这么用,用久了,大家都熟悉了,可能也就没有这个障碍了。

type和interface

关于两者的区别,大家可以看看这篇文章,本文主要说一下我的理解。

先说结论:我目前还是处于一种懵逼状态。我感觉type和insterface有太多的灰色地带,这就导致我们日常使用时,大部分情况下用谁都可以。我搞不懂ts为何要这样设计。

按照我前些年对java和C#的理解:(我不知道近几年javaC#有没有相关的语法变化)

如果自定义一个静态的类型,仅有一些属性,没有方法,就用type如果定义一种行为(行为肯定是需要方法的,仅属性是不够的),需要class实现,就用interface

但是查到的资料,以及查阅ts的类库lib.dom.d.ts和lib.es.d.ts源码,也都是用interface。我曾经一度很困惑,见的多了,就慢慢习惯成自然了,但问题并没有解决。

问题没有解决,但事情还是要继续做的,代码也是要继续写的,所以我就一直跟随大众,尽量用interface。

private和

两者都表示私有属性。背景不同:

private是ts中一开始就有的语法,而且目前只有ts有,ES规范没有。#是ES目前的提案语法,然后被ts3.8支持了。即,ts和ES都支持#。

如果仅对于ts来说,用哪个都一样。

但本文一开始提到过:ts只


转载请注明:http://www.kelongbinga.com/klss/7004.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了