Telerik blogs

Function overloading is a TypeScript feature that lets us define a function that accepts different kinds of arguments.

TypeScript mainly adds data type-checking capabilities that are missing in JavaScript. This makes programming easier since we don’t have to check the data type of variables and other values ourselves.

We can write our JavaScript programs in TypeScript. Then we can compile the TypeScript code into JavaScript so it can be run by JavaScript runtimes like the browser and Node.js.

One useful feature that is available in TypeScript is function overloading. Function overloading is a feature that lets us define a function that accepts different kinds of arguments.

In this article, we will look at how to implement function overloading in our TypeScript code.

Function Overloading in TypeScript

With TypeScript, we can define a function that accepts different kinds of arguments with function overloading.

To use this, we just have to add all the possible signatures for a function for the combinations of arguments we want the function to accept.

For example, to implement function overloading in TypeScript, we can write something like the following:

function add(a: number, b: number): number;
function add(a: string, b: string): number;

function add(a: unknown, b: unknown): number {
  if (typeof a === "string" && typeof b === "string") {
    return Number(a) + Number(b);
  } else if (typeof a === "number" && typeof b === "number") {
    return a + b;
  return 0;

We have two different signatures for the add function and they both have a return type set to number.

The first signature expects that both parameters a and b are numbers. And the second signature expects that both parameters a and b are strings.

To implement the function, we make a and b accept the unknown type, which lets us pass in anything for a and b.

In the function body, we check the data types of a and b with the typeof operator. If a and b are both strings, we convert a and b to numbers with the Number function and then get the sum of the numbers. If they’re both numbers, then we just return the sum of them. Otherwise, we return 0.

The unknown type is a type-safe counterpart of any. We can’t assign values with unknown type to any variable. But we can convert unknown type values to something else that matches the type of the variable.

With the typeof checks, we narrowed the types of a and b to one data type so TypeScript can infer the type and do the operations for the variables with the inferred type.

Then we can call add by writing:

const sum1 = add(1, 2);
const sum2 = add("1", "2");

We call add with the values that are expected by at least one of the signatures, so it passes the type checks done by the TypeScript compiler.

If we call add with values that aren’t expected by any of the signatures like:

const sum3 = add(1, "2");

Then the TypeScript compiler will raise a type-check error.

The function implementation’s signature must be more general than the overload signatures. This way, the function with overloads can accept different kinds of values expected by at least one of the signatures.

Method Overloading

We can also overload constructor or class methods.

For instance, we can write something like:

class Greeter {
  message: string;

  constructor(message: string) {
    this.message = message;

  greet(person: string): string;
  greet(persons: string[]): string;
  greet(person: unknown) {
    if (typeof person === "string") {
      return `${this.message}, ${person}!`;
    } else if (Array.isArray(person)) {
      return => `${this.message}, ${name}!`).join("\n");
    return "";

We define the Greeter class with the greet method in it. The greet method is overloaded with two different signatures. The first takes a string and returns a string. The second takes a string array and also returns a string.

In the implementation, we make the person function have an unknown type. We can add a return type or omit it since the TypeScript compiler can infer the return type from the implementation. We can check the value of person in the implementation with our own type checks.

First we check if person is a string with typeof person === "string". Then we check if person is an array with Array.isArray.

Next, we can create a Greeter instance and call the greet method by writing:

const greeter = new Greeter("Hello");
const message1 = greeter.greet("Jane");
const message2 = greeter.greet(["Alex", "Jane"]);

We create a Greeter instance with new. And then we call greet on the instance either with a string or an array of strings we specified with the signatures.

When to Use Function Overloading?

Ideally, we use function overloading only when we expect required arguments that have different types.

The examples above all have required parameters only but they’re allowed to have different types. If we expect some arguments that are optional, then we can use the optional parameter syntax instead.

For instance, instead of writing something like:

function foo(): string;
function foo(param1: string): string;
function foo(param1: string, param2: string): string;

function foo(...args: string[]) {
  return args.join("\n");

We can replace the overloads with optional parameters by writing something like:

function foo(param1?: string, param2?: string) {
  return [param1 ?? "", param2 ?? ""].join("\n");

Since we accept param1 and param2 as optional parameters, we can use ? to denote them as such.


Function overloading is a feature in TypeScript that lets us define a function that accepts different kinds of arguments.

We can use function overloading for specifying any kinds of function parameters. But ideally, we use them only for required parameters since TypeScript already has a simple optional function parameters syntax.

We can have function overloads for regular functions and class methods.

About the Author

John Au-Yeung

John Au-Yeung is a frontend developer with 6+ years of experience. He is an avid blogger (visit his site at and the author of Vue.js 3 By Example.

Related Posts


Comments are disabled in preview mode.