[英]TypeScript never type inference
有人可以解釋我為什么給出以下代碼:
let f = () => {
throw new Error("Should never get here");
}
let g = function() {
throw new Error("Should never get here");
}
function h() {
throw new Error("Should never get here");
}
推斷出以下類型:
f
是() => never
g
是() => never
h
是() => void
我希望h
的類型也是() => never
。
謝謝!
很好的問題。 不同之處在於f
和g
是函數表達式,其中h
是函數聲明。 當一個函數被throw
-只,它獲取的類型never
如果它是一個表達式, void
,如果它是一個宣言。
當然,上面的段落實際上並沒有幫助。 為什么函數表達式和函數聲明之間的行為存在差異? 讓我們看一下每種情況下的一些反例。
void
考慮一些代碼:
function iif(value: boolean, whenTrue: () => number, whenFalse: () => number): number {
return value ? whenTrue() : whenFalse();
}
let x = iif(2 > 3,
() => { throw new Error("haven't implemented backwards-day logic yet"); },
() => 14);
這段代碼好嗎? 它應該是! 當我們認為不應調用該函數或僅應在錯誤情況下調用該函數時,通常會編寫throw
函數。 但是,如果函數表達式的類型是void
,則對iif
的調用將被拒絕。
所以從這個例子中可以清楚地看出,只throw
函數表達式應該返回never
,而不是void
。 實際上這應該是我們的默認假設,因為這些函數符合never
的定義(在正確類型的程序中,無法觀察到類型為never
的值)。
never
返回閱讀上一節后,您應該會說“太好了,為什么不是所有的拋出函數都返回never
呢?”
簡短的回答是,事實證明這樣做是一個重大的突破性變化。 有很多代碼(尤其是在abstract
關鍵字之前的代碼)看起來像這樣
class Base {
overrideMe() {
throw new Error("You forgot to override me!");
}
}
class Derived extends Base {
overrideMe() {
// Code that actually returns here
}
}
但是返回void
的函數不能替代返回never
的函數(請記住,在正確類型的程序中,無法觀察到never
值),因此使Base#overrideMe
返回never
阻止Derived
提供任何非never
實現方法。
通常,雖然總是拋出的函數表達式經常作為Debug.fail
的占位符存在,但總是拋出的函數聲明非常罕見。 表達式經常被別名或忽略,而聲明是靜態的。 今天throw
s 的函數聲明實際上很可能在明天做一些有用的事情; 在沒有返回類型注釋的情況下,提供更安全的方法是void
(即暫時不要查看此返回類型)而不是never
(即此函數是一個黑洞,會吞噬當前執行堆棧)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.