[英]Typescript: ReturnType of overloaded function
ReturnType
給出的類型似乎取決於寫入重載簽名的順序
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
function applyChanges2(input: number): string
function applyChanges2(input: string): number
function applyChanges2(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
type Ret1 = ReturnType<typeof applyChanges1> // string
type Ret2 = ReturnType<typeof applyChanges2> // number
它似乎采用了最后一個重載簽名的返回類型,這似乎很隨意。 我期望Ret1
和Ret2
都是string | number
string | number
。 這種行為有原因嗎?
正如 Matt McCutchen 指出的那樣,這是ReturnType
和一般條件類型和多個重載簽名的限制。
然而,我們可以構造一個類型,該類型將返回最多任意數量的重載的所有重載返回類型:
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
function applyChanges2(input: number): string
function applyChanges2(input: string): number
function applyChanges2(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
type OverloadedReturnType<T> =
T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R ; (...args: any[]) : infer R } ? R :
T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R } ? R :
T extends { (...args: any[]) : infer R; (...args: any[]) : infer R } ? R :
T extends (...args: any[]) => infer R ? R : any
type RetO1 = OverloadedReturnType<typeof applyChanges1> // string | number
type RetO2 = OverloadedReturnType<typeof applyChanges2> // number | string
上面的版本最多可用於 4 個重載簽名(無論它們是什么),但可以輕松(如果不是很漂亮)擴展到更多。
我們甚至可以用同樣的方式得到可能參數類型的聯合:
type OverloadedArguments<T> =
T extends { (...args: infer A1) : any; (...args: infer A2) : any; (...args: infer A3) : any ; (...args: infer A4) : any } ? A1|A2|A3|A4 :
T extends { (...args: infer A1) : any; (...args: infer A2) : any; (...args: infer A3) : any } ? A1|A2|A3 :
T extends { (...args: infer A1) : any; (...args: infer A2) : any } ? A1|A2 :
T extends (...args: infer A) => any ? A : any
type RetO1 = OverloadedArguments<typeof applyChanges1> // [string] & [number]
type RetO2 = OverloadedArguments<typeof applyChanges2> // [number] & [string]
我有一個類似的問題——我需要根據我擁有的參數選擇精確重載的ReturnType
。
例如:
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: boolean): object
function applyChanges1(input: number | string | boolean): number | string | object {
return typeof input === "number" ? input.toString()
: typeof input === "boolean" ? { input }
: input.length;
}
// Needed:
type Ret11 = ReturnTypeWithArgs<typeof applyChanges1, [string]> // number
type Ret12 = ReturnTypeWithArgs<typeof applyChanges1, [number]> // string
type Ret13 = ReturnTypeWithArgs<typeof applyChanges1, [boolean]> // object
type Ret14 = ReturnTypeWithArgs<typeof applyChanges1, [number | string]> // number | string
type Ret15 = ReturnTypeWithArgs<typeof applyChanges1, [number | boolean]> // string | object
type Ret16 = ReturnTypeWithArgs<typeof applyChanges1, [number | string | boolean]> // number | string | object
因此,我根據上面@Titian的漂亮答案並使用Extract
創建了以下ReturnTypeWithArgs
實用程序。
type ReturnTypeWithArgs<T extends (...args: any[]) => any, ARGS_T> =
Extract<
T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4; } ? [A1, R1] | [A2, R2] | [A3, R3] | [A4, R4] :
T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; } ? [A1, R1] | [A2, R2] | [A3, R3] :
T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; } ? [A1, R1] | [A2, R2] :
T extends { (...args: infer A1): infer R1; } ? [A1, R1] :
never,
[ARGS_T, any]
>[1]
它就像一個魅力!
附注。 在我的真實情況下,我有 7 個重載,祝我好運! ;D
這是一個已知的限制。 TypeScript 團隊的建議是包含一個“最通用”的重載簽名作為最后一個重載簽名,例如:
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: number | string): number | string
function applyChanges1(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
Titian Cernicova-Dragomir 在他的回答中有一個更好的替代解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.