-
-
Notifications
You must be signed in to change notification settings - Fork 569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OverloadParameters
and OverloadReturnType
#585
Comments
Looks useful. I have had this need before too. |
// support 5 times overload at most
type OverloadedReturnType<T> =
T extends { (...args: any[]) : infer R; (...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 ; (...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;
function fn5(a: boolean): boolean;
function fn5(a: string): string;
function fn5(a: number): number;
function fn5(a: null): null;
function fn5(a: { a: string }): { a: string };
function fn5(a: string | number | boolean | null | { a: string } | { a: number }) : {a: string } | string | number | boolean | null | { a: number } {
return a;
}
// OK
type RFn5 = OverloadedReturnType<typeof fn5>;
function fn6(a: boolean): boolean;
function fn6(a: string): string;
function fn6(a: number): number;
function fn6(a: null): null;
function fn6(a: { a: string }): { a: string };
function fn6(a: { a: number }): { a: number };
function fn6(a: string | number | boolean | null | { a: string } | { a: number }) : {a: string } | string | number | boolean | null | { a: number } {
return a;
}
// boolean type is lost
type RFn6 = OverloadedReturnType<typeof fn6>;
```ts |
But can't implement pls refer to because inferring parameters from overload function type which is a union of function types, creates intersections instead of a unions .... type OverloadedParametersA<T> =
T extends { (...args: Array<infer P>): any; (...args: Array<infer P>): any; (...args: Array<infer P>): any; (...args: Array<infer P>): any; (...args: Array<infer P>): any; } ? P :
T extends { (...args: Array<infer P>): any; (...args: Array<infer P>): any; (...args: Array<infer P>): any; (...args: Array<infer P>): any; } ? P :
T extends { (...args: Array<infer P>): any; (...args: Array<infer P>): any; (...args: Array<infer P>): any; } ? P :
T extends { (...args: Array<infer P>): any; (...args: Array<infer P>): any; } ? P :
T extends { (...args: Array<infer P>): any; } ? P : never;
function fn5(a: boolean): boolean;
function fn5(a: string): string;
function fn5(a: number): number;
function fn5(a: null): null;
function fn5(a: { a: string }): { a: string };
function fn5(a: string | number | boolean | null | { a: string } | { a: number }) : {a: string } | string | number | boolean | null | { a: number } {
return a;
}
type PA = OverloadedParametersA<typeof fn5>; // actually, it is [boolean] & [string] & [number] & [null] & [{ a: string}] = never
type OverloadedParametersB<T> =
T extends { (...args: infer P): any; (...args: infer P): any; (...args: infer P ): any; (...args: infer P): any; (...args: infer P): any; } ? P :
T extends { (...args: infer P): any; (...args: infer P): any; (...args: infer P): any; (...args: infer P): any; } ? P :
T extends { (...args: infer P): any; (...args: infer P): any; (...args: infer P): any; } ? P :
T extends { (...args: infer P): any; (...args: infer P): any; } ? P :
T extends { (...args: infer P): any; } ? P : never;
type PB = OverloadedParametersB<typeof fn5>; // actually, it is [boolean] & [string] & [number] & [null] & [{ a: string}] = never
type OneOf<P> = P extends Array<infer P> ? P : never;
type OverloadedParametersC<T> =
T extends { (...args: infer P): any; (...args: infer P): any; (...args: infer P ): any; (...args: infer P): any; (...args: infer P): any; } ? OneOf<P> :
T extends { (...args: infer P): any; (...args: infer P): any; (...args: infer P): any; (...args: infer P): any; } ? OneOf<P> :
T extends { (...args: infer P): any; (...args: infer P): any; (...args: infer P): any; } ? OneOf<P> :
T extends { (...args: infer P): any; (...args: infer P): any; } ? OneOf<P> :
T extends { (...args: infer P): any; } ? OneOf<P> : never;
type PC = OverloadedParametersB<typeof fn5>; // actually, it is [boolean] & [string] & [number] & [null] & [{ a: string}] = never |
It's easier to split the function into overloads first and then extract returns/parameters function fn5(a: boolean): boolean;
function fn5(a: string): string;
function fn5(a: number): number;
function fn5(a: null): null;
function fn5<T extends 'a' | 'b'>(a: T): T;
function fn5(a: any) {
return a;
}
type OverloadsToTuple3<T> =
| 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,
] : OverloadsToTuple2<T>;
type OverloadsToTuple<T> =
| OverloadsToTuple5<T>
type PD = OverloadsToTuple<typeof fn5>
// ^?
// type PD = [(a: boolean) => boolean, (a: string) => string,
// (a: number) => number, (a: null) => null, (a: "a" | "b") => "a" | "b"]
type Params = Parameters<OverloadsToTuple<typeof fn5>[number]>
// ^?
// type Params = [a: boolean] | [a: string] | [a: number] | [a: null] | [a: "a" | "b"]
type Returns = ReturnType<OverloadsToTuple<typeof fn5>[number]>
// ^?
// type Returns = string | number | boolean | null
type Match = Extract<OverloadsToTuple<typeof fn5>[number], (s: 'a') => any>
// ^?
// type Match = ((a: string) => string) | ((a: "a" | "b") => "a" | "b")
type MatchReturn = ReturnType<Extract<OverloadsToTuple<typeof fn5>[number], (s: 'a') => any>>
// ^?
// type MatchReturn = string |
OMG @Dimava, you literally saved my entire project with this comment. solana-labs/solana-web3.js#1760 |
This kind of gives an erroneous tuple back when there's less than 5 overloads: function fn3(a: boolean): boolean;
function fn3(a: string): string;
function fn3(a: number): number;
function fn3(a: any) {
return a;
}
type Overloads = OverloadsToTuple<typeof fn3>
// ^?
// [(a: boolean) => boolean, (a: boolean) => boolean, (a: boolean) => boolean, (a: string) => string, (a: number) => number] This can be improved just by de-duping the tuple: /**
* Dedupe tuple elements.
* For example,
* ```
* type Set = Dedupe<[number, string, boolean, string, number]>;
* // Set == [number, string, boolean]
* ```
*/
export type Dedupe<T extends unknown[], A extends unknown[] = []> = T extends [infer P, ...infer R]
? P extends A[number]
? Dedupe<R, A>
: Dedupe<R, [...A, [P] extends [boolean] ? boolean : P]>
: A;
type OverloadsToTuple<T> =
| Dedupe<OverloadsToTuple5<T>>
type Overloads = OverloadsToTuple<typeof fn3>
// ^?
// [(a: boolean) => boolean, (a: string) => string, (a: number) => number] Edit: So you can essentially remove type Dedupe<T extends unknown[], A extends unknown[] = []> = T extends [infer P, ...infer R]
? P extends A[number]
? Dedupe<R, A>
: Dedupe<R, [...A, [P] extends [boolean] ? boolean : P]>
: A;
type Overloads<T> = Dedupe<
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: infer P9): infer R9;
(...args: infer P10): infer R10;
(...args: infer P11): infer R11;
(...args: infer P12): infer R12;
(...args: infer P13): infer R13;
(...args: infer P14): infer R14;
(...args: infer P15): infer R15;
(...args: infer P16): infer R16;
(...args: infer P17): infer R17;
(...args: infer P18): infer R18;
(...args: infer P19): infer R19;
(...args: infer P20): infer R20;
// ...
} ? [
(...args: P1): R1,
(...args: P2): R2,
(...args: P3): R3,
(...args: P4): R4,
(...args: P5): R5,
(...args: P6): R6,
(...args: P7): R7,
(...args: P8): R8,
(...args: P9): R9,
(...args: P10): R10,
(...args: P11): R11,
(...args: P12): R12,
(...args: P13): R13,
(...args: P14): R14,
(...args: P15): R15,
(...args: P16): R16,
(...args: P17): R17,
(...args: P18): R18,
(...args: P19): R19,
(...args: P20): R20,
// ...
] : never
>; |
Basically native
Parameter
andReturnType
do not handle overloaded interfaces.Here is a workaround: microsoft/TypeScript#14107 (comment)
Upvote & Fund
The text was updated successfully, but these errors were encountered: