Function overloading allows us to declare multiple functions with the same name but with different parameters and implementations. It is possible to overload functions in TypeScript.

function display(message: string | number) {
  if (typeof message === "string") {
    return message.toUpperCase();
  }
  return message;
}

We have a function display() which takes a string or a number as a parameter. If the parameter is a string, it returns the string converted to uppercase, and if the parameter is a number, it simply returns the number.

We know for sure that if we pass a string as a parameter, display() function will always return a string.

let content = display("Hello");

content.trim(); // ❌ Property 'trim' does not exist on type 'string | number'.

If I try to apply trim() function on the output of display() function, it will not allow me to do so. This is because Typescript will complain, Property 'trim' does not exist on type 'string | number'.

One way to solve this issue is to overload the function. Because we know display() function will always return a string if the parameter passed to it is a string, we can write:

function display(message: string): string;

function display(message: string | number) {
  if (typeof message === "string") {
    return message.toUpperCase();
  }
  return message;
}

let content = display("Hello");

content.trim(); // ✅ allowed

We now inform TypeScript that if the parameter is a string, the function will always return a string.

function display(message: string): string;

Similarly, we can also write a function definition for a number. If the parameter is a number, the function will always return a number.

function display(message: string): string;
function display(message: number): number;

function display(message: string | number) {
  if (typeof message === "string") {
    return message.toUpperCase();
  }
  return message;
}

let content = display(10.3143);

content.toFixed(); // ✅ allowed