簡體   English   中英

TypeScript 從不進行類型推斷

[英]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

謝謝!

很好的問題。 不同之處在於fg是函數表達式,其中h是函數聲明 當一個函數被throw -只,它獲取的類型never如果它是一個表達式, void ,如果它是一個宣言。

當然,上面的段落實際上並沒有幫助。 為什么函數表達式和函數聲明之間的行為存在差異? 讓我們看一下每種情況下的一些反例。

壞主意 #1:使拋出函數表達式返回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的值)。

壞主意#2:讓拋出的函數聲明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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM