TypeScript 中的重载函数类型
本文其实主要回答了三个问题:
重载函数是如何定义的呢?
如何获取重载函数的返回类型?
又如何获取重载函数的参数类型呢?
我们先定义一个简单的重载函数:
typescript
function fn(): void;
function fn(a: string): string;
function fn(a: number): number;
function fn<T extends 'a' | 'b'>(a: T): T;
function fn<T extends { a: string }>(a: T): T;
function fn(a: string, b: number): [string, number];
function fn(a?: any) {
return a;
}然后尝试获取函数的参数类型:
typescript
type ParametersFn = Parameters<typeof fn>;
type ReturnTypeFn = ReturnType<typeof fn>;此时我们发现, 只有最后一个 overload 签名的参数类型和返回值类型被返回了...
那到底如何才能正确获取重载函数的所有参数类型和返回值类型呢?
首先, 我们来研究一下如何正确的定义一个重载函数类型, 参考 TypeScript handbook 中 的Call Signatures, 我们很容易写出上面的重载函数的类型:
typescript
type F = {
(): void;
(a: string): string;
(a: number): number;
<T extends 'a' | 'b'>(a: T): T;
<T extends { a: string }>(a: T): T;
(a: string, b: number): [string, number];
};接着, 试着写出一个OverloadReturnType<T>来获取返回值类型, 但是问题在于 overload 签名的数量不是固定的, 如何来进行定义呢? 这里只能采用一个折中的写法, 把每个方法 签名类型转换到一个 Tuple 类型中, 以下写法最多可以支持 8 个函数重载签名:
typescript
type Fn = (...args: any) => any;
type OverloadReturns<F extends Fn> = ReturnType<OverloadSignatures<F>>;
type OverloadParameters<F extends Fn> = Parameters<OverloadSignatures<F>>;
type MatchOverload<F extends Fn, P extends Fn> = Extract<OverloadSignatures<F>, P>;
type OverloadSignatures<F extends Fn> = OverloadsToTuple<F>[number];
type OverloadsToTuple<T> = T extends {
(...args: infer P1): infer R1;
(...args: infer P2): infer R2;
(...args: infer P3): infer R3;
(...args: infer P4): infer R4;
(...args: infer P5): infer R5;
(...args: infer P6): infer R6;
(...args: infer P7): infer R7;
(...args: infer P8): infer R8;
}
? [
(...args: P1) => R1,
(...args: P2) => R2,
(...args: P3) => R3,
(...args: P4) => R4,
(...args: P5) => R5,
(...args: P6) => R6,
(...args: P7) => R7,
(...args: P8) => R8
]
: T extends {
(...args: infer P1): infer R1;
(...args: infer P2): infer R2;
(...args: infer P3): infer R3;
(...args: infer P4): infer R4;
(...args: infer P5): infer R5;
(...args: infer P6): infer R6;
(...args: infer P7): infer R7;
}
? [(...args: P1) => R1, (...args: P2) => R2, (...args: P3) => R3, (...args: P4) => R4, (...args: P5) => R5, (...args: P6) => R6, (...args: P7) => R7]
: T extends {
(...args: infer P1): infer R1;
(...args: infer P2): infer R2;
(...args: infer P3): infer R3;
(...args: infer P4): infer R4;
(...args: infer P5): infer R5;
(...args: infer P6): infer R6;
}
? [(...args: P1) => R1, (...args: P2) => R2, (...args: P3) => R3, (...args: P4) => R4, (...args: P5) => R5, (...args: P6) => R6]
: T extends {
(...args: infer P1): infer R1;
(...args: infer P2): infer R2;
(...args: infer P3): infer R3;
(...args: infer P4): infer R4;
(...args: infer P5): infer R5;
}
? [(...args: P1) => R1, (...args: P2) => R2, (...args: P3) => R3, (...args: P4) => R4, (...args: P5) => R5]
: T extends { (...args: infer P1): infer R1; (...args: infer P2): infer R2; (...args: infer P3): infer R3; (...args: infer P4): infer R4 }
? [(...args: P1) => R1, (...args: P2) => R2, (...args: P3) => R3, (...args: P4) => R4]
: T extends { (...args: infer P1): infer R1; (...args: infer P2): infer R2; (...args: infer P3): infer R3 }
? [(...args: P1) => R1, (...args: P2) => R2, (...args: P3) => R3]
: T extends { (...args: infer P1): infer R1; (...args: infer P2): infer R2 }
? [(...args: P1) => R1, (...args: P2) => R2]
: T extends { (...args: infer P1): infer R1 }
? [(...args: P1) => R1]
: never;RUN ME 尝试着使用一下, 结果非常完美!