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. This is a missing feature or design limitation of TypeScript; see microsoft/TypeScript#29732 for a relevant feature request.
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 (this is still true as of TypeScript 4.8; recursive conditional types don't help). 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