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;
}
然后尝试获取函数的参数类型:
type ParametersFn = Parameters<typeof fn>
type ReturnTypeFn = ReturnType<typeof fn>
此时我们发现, 只有最后一个overload签名的参数类型和返回值类型被返回了...
那到底如何才能正确获取重载函数的所有参数类型和返回值类型呢?
首先, 我们来研究一下如何正确的定义一个重载函数类型, 参考TypeScript handbook中的Call Signatures, 我们很容易写出上面的重载函数的类型:
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个函数重载签名:
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 尝试着使用一下, 结果非常完美!