SoFunction
Updated on 2025-03-01

TypeScript uses Tuple Union to declare function overload

question:

After adding multiple signatures to a function in TypeScript, you still need to add corresponding code to judge and obtain the corresponding parameters from different signature parameter lists.Common writing methods in the past:

function refEventEmitter(event?: string): void;
function refEventEmitter(event: string, callback: () => void): void;
function refEventEmitter(callback: () => void): void;
function refEventEmitter(
  eventOrCallback?: string | (() => void),
  callback?: () => void,
): void {
  let event: string | undefined;

  if (typeof eventOrCallback === 'function') {
    callback = eventOrCallback;
  } else {
    event = eventOrCallback;
  }

  // ...
}

In this process, because the original parameter list is directly flattened by the serial number, the type correlation between parameters needs to be ensured to be correct.

Skill:

At this time we can usetuple union parameter type,To handle various function overloading situations without brains:

function refEventEmitter(event?: string): void;
function refEventEmitter(event: string, callback: () => void): void;
function refEventEmitter(callback: () => void): void;
function refEventEmitter(
  ...args:
    | [event?: string]
    | [
        event: string,
        callback: () => unknown,
      ]
    | [callback: () => unknown]
): void {
  let [event, callback] =
     === 2
      ? args
      : typeof args[0] === 'function'
      ? [undefined, args[0]]
      : [args[0], undefined];

  // ...
}

In fact, the signature list above is no longer needed at this time:

function refEventEmitter(
  ...args:
    | [event?: string]
    | [
        event: string,
        callback: () => unknown,
      ]
    | [callback: () => unknown]
): void {
  let [event, callback] =
     === 2
      ? args
      : typeof args[0] === 'function'
      ? [undefined, args[0]]
      : [args[0], undefined];

  // ...
}
This article has actually been delayed for a while. When I was writing it, I found that TypeScript has built-in refactoring option "Convert overload list to single signature". You can change the overload list into a parameter tuple union with one click.

However, there are still problems here. The typeof condition judgment in TypeScript cannot narrow the entire object, but can only narrow a certain element or attribute that is reached by typeof. In the above example, if it is not just neededargs[0]There will be problems.

At this point we can introduce a tool function isTypeOfProperty(object, key, type)

At this point the implementation becomes:

function refEventEmitter(
  ...args:
    | [event?: string]
    | [
        event: string,
        callback: () => unknown,
      ]
    | [callback: () => unknown]
): void {
  let [event, callback] =
     === 2
      ? args
      : isTypeOfProperty(args, 0, 'function')
      ? [undefined, args[0]]
      : [args[0], undefined];

  // ...
}

This is the article about TypeScript using Tuple Union to declare function overloading. For more related contents of TypeScript to declare function overloading, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!