TypeScript类型推论(Type Inference)
要完全理解類型推論需要完整理解類型上下文,并且理解TS對于是否可以使用類型推論是基于靜態分析完成的。
上下文類型應用在許多地方。常見的例子包括函數調用的參數,賦值的右手端位置,類型斷言,對象和數組的成員,和返回語句。上下文類型還充當最佳公共類型中的候選類型。
TS中需要為每個JS名字規定類型,而名字出現在對應的上下文中則會自動獲得類型,若沒有對應的上下文,這個名字則會自動獲得類型any。
名字:通過聲明語句聲明的名字,例如var、let、const、function a() {}、class A {}、import A from ‘.a’、函數參數等,都會在JS環境中添加一個名字,而TS可以給這個名字指定類型。
在JS中名字的聲明是可以在上面提到的常見例子指定的位置,函數參數調用、賦值右手端位置、對象數組成員、返回語句。
函數調用的參數
interface Cb {(a: number): void; } interface Fn {(cb: Cb): void; }const fn: Fn = function (cb) {}fn(function (a) { // 這里a的類型是numberconsole.log(a + 1) })因為fn這個名字是類型Fn,而Fn類型的入參是類型Cb,所以在fn使用匿名函數作為入參調用的時候TS可以知道這個匿名函數對應的位置是類型Cb,換句話說匿名函數當前的類型上下文是Cb。而Cb要求入參是number類型,所以推斷出匿名函數的參數a是number類型。
賦值的右手端位置
interface Cb {(a: number): void; }const fn: Cb = function (a) {console.log(a + 1) }fn是類型Cb,因為Cb要求入參是number類型,所以TS推斷出對應位置匿名函數的入參是number類型。
對象和數組的成員
interface Cb {(a: number): void; } interface Obj {fn: Cb } const obj: Obj = {fn: function (a) {console.log(a + 1)} }obj是類型Obj,而Obj具有屬性fn是類型Cb。因為Cb要求入參是number類型,所以TS推斷出對象obj.fn右手端對應位置匿名函數的入參是number類型。
返回語句
interface Cb {(a: number): void }interface Fn {(): Cb }const fn: Fn = function () {return (a) => {console.log(a + 1)} }在這例子里,返回的匿名函數獲得類型上下文Cb,而Cb要求入參是number,所以匿名函數的入參被推斷出是number類型。
上面的幾種類型都可以認為名字出現在了賦值的右手端,而被復制的名字可以給這個值提供對應的類型上下文。
類型斷言
interface Fn {(a: number): void; }const fn = function (a) {console.log(a + 1); } as Fn;在這里匿名函數賦值給變量fn而fn本身是沒有類型的,所以沒辦法推斷匿名函數的入參a的類型,但是我們使用類型給這個匿名函數指定了類型上下文Fn,讓TS具有了推算參數a的依據,得出參數a是number類型。
小結
類型推斷起作用的條件是名字出現在對應的上下文位置,而這個上下文可以通過賦值操作的左手端提供,也可以使用類型斷言直接提供。這樣TS可以根據對應的類型推斷出對應變量的類型。
一些意外
interface Fn {(a: number): void; }function fn(a) {}let a: Fn = fn在這個例子里,TS無法推斷出函數fn的參數a是number類型,因為賦值操作提供的類型上下文在右手端,而fn這個函數聲明的位置,并不是右手端。對應的右手端位置并不是函數聲明,而是函數聲明的引用。所以TS無法靜態分析出fn中a的類型。
還有一個原因是fn的使用并不唯一,在這里我們將fn賦值給Fn類型的變量a,我們完全可以將它再賦值給Fn1類型的變量b,所以這種情況下fn中a的類型是由運行時決定的,無法靜態分析出來。
這里Fn1要求入參a的類型是string,所以fn的入參a既可能是number也可能是string,只有運行這個函數的時候才能確定知道參數a是什么類型。所以在這個例子中a會自動獲得隱式類型any。
進行如下修改:
interface Fn {(a: number): void; }let a: Fn = function fn(a) {}在這里fn是一個表達式,并不會再當前環境中新建一個名字fn,換句話說這個fn不會再用在別的地方,并且a這個名字直接出現在了右手端對應位置,所以這個fn函數可以得到類型上下文Fn,從而推斷出參數a的類型是number。
總結
以上是生活随笔為你收集整理的TypeScript类型推论(Type Inference)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TypeScript 交叉类型(inte
- 下一篇: Chrome不显示OPTIONS请求的解