有没有办法从重载的 TS 方法中提取所有函数签名?

6 overloading typescript

基本上我只是想包装一个具有多个签名的函数。有没有一种干净的方法可以做到这一点,而无需重新硬编码所有签名?我只想bar在下面接受任何相同的论点foo

declare function foo(x: string): number;
declare function foo(x: string, y: number): 42;
declare function foo(x: number): string;

type fooArgs = Parameters<typeof foo>; // this only extracts from the last signature
declare function bar(...args: fooArgs): string[]

const a = foo(123);        // fine
const b = foo('123');      // fine
const c = foo('123', 456); // fine

const x = bar(123);        // fine
const y = bar('123');      // fails because it expects (x: number) => string
const z = bar('123', 456); // fails
Run Code Online (Sandbox Code Playgroud)

TS 游乐场

cap*_*ian 1

这是设计使然。它总是返回最后一个重载的签名。参见本期/28789

然而,还有另一种方法。

请记住,重载只是函数类型的交集。

我们可以声明一个类型来保存所有的重载签名:


type Signatures = {
    1: (x: string) => number,
    2: (x: string, y: number) => 42
    3: (x: number) => string
}
Run Code Online (Sandbox Code Playgroud)

现在,为了创建重载,我们需要获取所有对象属性的并集并将它们相交。


// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
    k: infer I
) => void
    ? I
    : never;

type Values<T> = T[keyof T]

type Overloading = UnionToIntersection<Values<Signatures>>
Run Code Online (Sandbox Code Playgroud)

它按预期工作:

declare const foo: Overloading;

const a = foo(123); // string
const b = foo('123'); // number
const c = foo('123', 456); // 42
Run Code Online (Sandbox Code Playgroud)

现在,很容易获得所有允许参数的并集:


//  [x: string] | [x: string, y: number] | [x: number]
type fooArgs = Parameters<Values<Signatures>>;
declare function bar(...args: fooArgs): string[]


const x = bar(123); // string[]
const y = bar('123'); // string[]
const z = bar('123', 456); // string[]
Run Code Online (Sandbox Code Playgroud)

整个代码:



type Signatures = {
    1: (x: string) => number,
    2: (x: string, y: number) => 42
    3: (x: number) => string
}

// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
    k: infer I
) => void
    ? I
    : never;

type Values<T> = T[keyof T]

type Overloading = UnionToIntersection<Values<Signatures>>

declare const foo: Overloading;

const a = foo(123); // string
const b = foo('123'); // number
const c = foo('123', 456); // 42


//  [x: string] | [x: string, y: number] | [x: number]
type fooArgs = Parameters<Values<Signatures>>;
declare function bar(...args: fooArgs): string[]


const x = bar(123); // string[]
const y = bar('123'); // string[]
const z = bar('123', 456); // string[]
Run Code Online (Sandbox Code Playgroud)

操场