question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Parameter type interface for overloaded functions as union type

See original GitHub issue

Search Terms

parameter type interface for overloaded functions as union type

Suggestion

The following method:

/**
 * Obtain the parameters of a function type in a tuple
 */
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;

Could return an union type when used with overloaded methods instead of the last overload

Use Cases

Message event name safety defined by overloaded signatures Workaround is to use an enum instead if working in a typescript context.

Examples

export interface Emitter {
    emit(event: 'event_1'): void;
    emit(event: 'event_2'): void;
    emit(event: 'event_3'): void;
    emit(event: 'event_4'): void;
}

type EventName = Parameters<Emitter["emit"]>[0]
// is -> type EventName = "event_4"
// wanted -> type EventName = "event_1" | "event_2" | "event_3" | "event_4"
const a: EventName = "event_4";
const b: EventName = "event_1";
// error, because -> const b: "event_4"

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:92
  • Comments:28 (3 by maintainers)

github_iconTop GitHub Comments

28reactions
fatcerberuscommented, Jun 28, 2019

The case here though was infer over the entire parameter list which in the case above would yield [string,string] | [number,number]—which precisely describes the valid inputs to fn.

16reactions
jcalzcommented, Jan 21, 2021

It’s not perfect but you can tease some info out of the compiler about overloads… up to an arbitrary fixed number of overloads, modulo some weird bugs with zero-arg function types (#28867)

Click to expand
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

interface Emitter {
    emit(event: 'event_1'): void;
    emit(event: 'event_2'): void;
    emit(event: 'event_3'): void;
    emit(event: 'event_4'): void;
}

type EmitterEmitParams = OverloadedParameters<Emitter["emit"]>
// type EmitterEmitParams = [[event: "event_1"], [event: "event_2"], [event: "event_3"], [event: "event_4"]]

type EventName =  OverloadedParameters<Emitter["emit"]>[number][0]
// type EventName = "event_1" | "event_2" | "event_3" | "event_4"

const a: EventName = "event_4";
const b: EventName = "event_1";

Playground link

Read more comments on GitHub >

github_iconTop Results From Across the Web

Overloaded method of an interface cannot accept a union type ...
The method can accept either null or string value as a parameter. I define a union type: string | null and pass it...
Read more >
Overloaded functions in TypeScript - Damir's Corner
In this post, I presented an example of how function overload signatures, union types, and custom type guards can be used to tell...
Read more >
Type polymorphic functions in TypeScript - Zhenghao
The argument's type could either be a string or boolean , so we use a union type to model this. Then, we use...
Read more >
Documentation - Advanced Types - TypeScript
A predicate takes the form parameterName is Type , where parameterName must be the name of a parameter from the current function signature....
Read more >
Overload Functions to Enrich your Definition - Learn TypeScript
The advantage of overloaded functions is clarity for the consumer. A consumer sees several functions with different signatures (parameters and return types).
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found