Parameters generic of overloaded function doesn’t contain all options

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

Leave a Comment