[英]Type conversions and conditional return types in TypeScript
我正在嘗試在 TypeScript 中的自定義類型之間進行轉換並使用條件返回類型。 但是,TS 不會讓我,因為以下不編譯:
type AString = { a: string };
type ANumber = { a: number };
type A<T> = T extends string ? AString : ANumber;
function isANumber(x: any): x is ANumber {
return x && typeof x.a === "number";
}
function isAString(x: any): x is AString {
return x && typeof x.a === "string";
}
type BString = { b: string };
type BNumber = { b: number };
type B<T> = T extends string ? BString : BNumber;
function a2b<T>(a: A<T>): T extends string ? BString : BNumber {
if (isAString(a)) return { b: a.a } as BString;
if (isANumber(a)) return { b: a.a } as BNumber;
}
有人抱怨函數末尾缺少 return,TS 可能知道,但這不是我的痛點。 更重要的是,無論是BString
也不BNumber
可以被分配到T extends string ? BString : BNumber
T extends string ? BString : BNumber
。 更令人困惑的是,兩者都不能分配給B<T>
。 我錯過了條件類型的什么?
PS:使用聯合類型可以解決這個例子中的編譯器錯誤,但在我的實際代碼中不會。
問題是打字稿不能使isAString(a)
等價於檢查T extends string
邏輯跳轉。 它縮小了變量a
的定義而不是泛型T
。 它仍然認為T
可能是因為存在,所以它抱怨返回BString
或BNumber
分別,因為它不知道你正在返回正確的。
你的as BString
as BNumber
和as BNumber
聲明實際上並不是必需的,因為打字稿已經知道它在第一種情況下處理{b: string}
,在第二種情況下處理{b: number}
。 它未能實現的跳躍是這些類型與T
有任何關系。
關閉它的最簡單方法是在兩種情況下都使用as B<T>
。
另一個簡單的解決方案是讓您的返回類型直接依賴於它可以從T
推斷出的值。
function a2b<T extends AString | ANumber>(a: T): {b: T['a']} {
return { b: a.a };
}
如果泛型T
直接描述變量a
那么打字稿可以做出更好的推斷,並且會理解如果a
是 x 而不是T
必須是 x。 所以我盡量讓泛型適用於整個變量。 Typescript 並不是最擅長逆向工作。
盡管如此,我仍然無法在這里找到一個非常好的解決方案。 它只是不喜歡extends
。 如果我說T extends AString | ANumber
T extends AString | ANumber
並反向工作以獲取返回類型的string
或number
,將AType
定義為T['a']
工作正常,但是如果AType
是T extends AString ? string : number
T extends AString ? string : number
然后它會中斷。 游樂場鏈接
它與extends
真正含義有關,文字字符串和文字數字擴展了字符串和數字。
看看這個錯誤,我想你會理解這個問題:
function a2b<T>(a: A<T>): {b: T} {
if (isAString(a)) return { b: a.a }; // error TS2322: Type 'string' is not assignable to type 'T'.
// 'T' could be instantiated with an arbitrary type which could be unrelated to 'string'.
if (isANumber(a)) return { b: a.a };
}
所以我們知道aa
是一個string
並且T extends string
,但我們仍然不知道aa
可以分配給T
因為你可能有這樣的情況T
是some string
的文字some string
而a
是{a: "other string"}
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.