How to write function overloads in TypeScript?

January 3, 2022 - 4 min read

The function overload signatures are written above the original function implementation signature without the function body part in TypeScript.

TL;DR

// overload signature when argument
// value is of `string` type
// 👇 this is an overload signature 👇
function getLength(data: string): number;

// overload signature when argument
// value is of any `array` type
// 👇 this is also an overload signature 👇
function getLength(data: any[]): number;

// function that return the
// value of the `length` property
// 👇 this is the implementation signature 👇
function getLength(data: any): number {
  return data.length;
}

// call the function with
// different argument value types
getLength("Hello World!"); // 12

getLength(["John", "Roy", "Lily"]); // 3

To write a good function overload in TypeScript, one has to understand why it is used in the first place.

Reasons for using a function overload:

  • A function overload is only used to make the life of the programmer who is calling or invoking the function easier.
  • A function overload doesn't change the function logic itself but only the parameter count and its type.
  • A function overload is used to have more readability than having any other features.

To understand a little better, let's start by writing a simple function that accepts some value as a parameter and return the value of the length property associated with it.

It can be done like this,

// function that return the
// value of the `length` property
function getLength(data: any): number {
  return data.length;
}

We also know that the length property is available only to the string and array value types so let's try to make the function much more usable by writing 2 overload signatures above the original signature but without the function body part.

First, let's write the function overload signature when the argument value is of string type.

It can be done like this,

// overload signature when argument
// value is of `string` type
function getLength(data: string): number;

// function that return the
// value of the `length` property
function getLength(data: any): number {
  return data.length;
}

As you can see that we have written the overload signature above the original signature without the function body part and that signature ends with the ; symbol (semi-colon).

Now let's also write the function overload signature when the argument value is of any array type.

Let's write this overload signature below the string overload signature.

It can be done like this,

// overload signature when argument
// value is of `string` type
// 👇 this is an overload signature 👇
function getLength(data: string): number;

// overload signature when argument
// value is of any `array` type
// 👇 this is also an overload signature 👇
function getLength(data: any[]): number;

// function that return the
// value of the `length` property
// 👇 this is the implementation signature 👇
function getLength(data: any): number {
  return data.length;
}

The original signature where the parameter data has the type of any is called the implementation signature in TypeScript and this cannot be directly called by the user who is invoking the function.

Implementation signatures are there to associate with the function overloads parameters and thus functions overload signatures must also match the implementation signature.

Only function overload signatures are callable.

Now let's try to call the getLength function with the value of a string type and an array type like this,

// overload signature when argument
// value is of `string` type
// 👇 this is an overload signature 👇
function getLength(data: string): number;

// overload signature when argument
// value is of any `array` type
// 👇 this is also an overload signature 👇
function getLength(data: any[]): number;

// function that return the
// value of the `length` property
// 👇 this is the implementation signature 👇
function getLength(data: any): number {
  return data.length;
}

// call the function with
// different argument value types
getLength("Hello World!"); // 12

getLength(["John", "Roy", "Lily"]); // 3

As you can see that both calls to the getLength function are valid and are handled appropriately.

NOTE: If you are using the VSCode as your code editor it shows the various function call signatures available to the user if you hover the function.

It may look like this,

See the above code live in codesandbox.

That's all 😃!

Feel free to share if you found this useful 😃.