簡體   English   中英

打字稿:重載函數的返回類型

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

它似乎采用了最后一個重載簽名的返回類型,這似乎很隨意。 我期望Ret1Ret2都是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.

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