Parameters generic of overloaded function doesn't contain all options
Given an overloaded function example
.
function example(a: string): number
function example(a: string, b?: string): number {
return 1
}
type Result = Parameters<typeof example>
I'd expect Result to contain ALL options for arguments of example
, not just the first / top-most argument set. How can I get the parameters?
In the answers to the question this duplicates the limitation mentioned in @ford04's answer here, that infer
only looks at the last overloaded signature, is acknowledged.
But this answer shows it's not completely impossible; you can tease out some information about overloads, at least for functions with up to some arbitrary fixed number of them. But it's hairy and ugly and there might be bugs in it, see microsoft/TypeScript#28867. Here's one way of doing it:
type Overloads<T> =
T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
(...args: infer A4): infer R4
} ? [
(...args: A1) => R1,
(...args: A2) => R2,
(...args: A3) => R3,
(...args: A4) => R4
] : T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3
} ? [
(...args: A1) => R1,
(...args: A2) => R2,
(...args: A3) => R3
] : T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2
} ? [
(...args: A1) => R1,
(...args: A2) => R2
] : T extends {
(...args: infer A1): infer R1
} ? [
(...args: A1) => R1
] : any
type OverloadedParameters<T> =
Overloads<T> extends infer O ?
{ [K in keyof O]: Parameters<Extract<O[K], (...args: any) => any>> } : never
type OverloadedReturnType<T> =
Overloads<T> extends infer O ?
{ [K in keyof O]: ReturnType<Extract<O[K], (...args: any) => any>> } : never
The Overloads<T>
type alias takes a function type T
and returns a tuple of its call signatures (for up to four overloads). And OverloadedParameters<T>
and OverloadedReturnType<T>
map Parameters<T>
and ReturnType<T>
over that tuple, respectively.
Let's see it in action (after correcting your example so that it actually has multiple overloads, as done in the other answer):
function example(a: string): number
function example(a: string, b: string): number
function example(a: string, b?: string): number {
return 1
}
type ExampleOverloads = Overloads<typeof example>
// type ExampleOverloads = [(a: string) => number, (a: string, b: string) => number]
type ExampleParameters = OverloadedParameters<typeof example>
// type ExampleParameters = [[string], [string, string]]
Looks reasonable to me. Okay, hope that helps; good luck!
Link to code