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