簡體   English   中英

如何斷言 TypeScript 泛型類型

[英]How to assert TypeScript Generics type

我試圖用映射類型和泛型合成這些重載,

function x(_: BooleanConstructor): boolean
function x(_: StringConstructor): string
function x(_: NumberConstructor): number
function x<T>(_: Constructor<T>): T

但是我遇到了很多困難,尤其是這個,

我想知道為什么以下代碼(在 TypeScript 游樂場中打開)不起作用。

export type Constructor<T> = new (...args: any[]) => T
export type MappedResult<T> =
    T extends Boolean ? boolean :
    T extends Number ? number :
    T extends String ? string :
    T

function make<T, Ctor = Constructor<T>, Result = MappedResult<T>>(ctor: Ctor): Result {
    if (ctor === String) { return '' } // would produce error
    throw new Error()
}

const str = make<String, StringConstructor, string>(String) // string!
const wrongInferenceStr = make(String) // would be {}

我的理解是T更像是 TypeScript 3.0 中新的unknown類型,所以我必須斷言它的身份,有什么辦法可以解決這個問題嗎?

更新

使用 jcalz 的答案,我嘗試使用this ,但沒有運氣。

簡而言之,我認為編譯器有問題。 問題在這里

為了在調用make時獲得正確的推理,最好使其簽名要求盡可能簡單的推理。 這意味着:為編譯器提供最少的決策空間,並盡可能簡單地做出決策。 例如,只有一個類型參數與ctor參數的類型完全對應,然后使用條件類型來計算輸出的相關類型。 像這樣:

declare function make<C extends Constructor<any>>(ctor: C): 
  MappedResult<C extends Constructor<infer T> ? T : never>;

現在,你得到

const str = make(String); // string

至於make實現內部的錯誤,編譯器一般不夠聰明,無法C泛型類型參數的類型縮小StringConstructor ,會報錯。 處理這個問題的最簡單方法通常是對調用者簽名使用單個重載,並使實現簽名更加寬松(但類型安全性較低)。 例如:

function make<C extends Constructor<any>>(ctor: C): MappedResult<C extends Constructor<infer T> ? T : never>;
function make(ctor: Constructor<any>): any {
    if (ctor === String) { return '' } // no error now
    throw new Error()
}

這是有效的,但您必須小心實現,因為返回類型是any 這類似於斷言。 不確定這里是否有一種聰明的方法來保證類型安全......但你可能不需要它。


希望有幫助。 祝你好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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