TypeOfNaN

How to condition a function's output type based on its input type in Typescript

Nick Scialli
September 10, 2022

Typescript is most helpful when we can use it to assert things that we know are true about our code. Sometimes, however, it can be difficult to figure out the right incantation to make that happen.

In this post, we’ll learn how to condition a function’s output type based on its input type.

An example

Let’s create a contrived example. We’ll have a function flipType that takes a number or a string as an argument. If the argument is a number, the return type should be a string, and if the argument is a string, the return type should be a number.

If we were to try to naively implement this, it might look something like this:

function flipType(arg: number | string): number | string {
  if (typeof arg === 'string') {
    return 5;
  }
  return 'some string';
}

This will compile just fine, but it doesn’t work how we want it to—it doesn’t narrow the return type of our function when we call it. For example:

const result1 = flipType('hello');
const result2 = flipType(5);

result1 should be a number type and result2 should be a string type, but they aren’t being narrowed and are bout number | string typed.

Overloads to the rescue

We’re saved here by function overloads. Function overloads let you define different scenarios for the function just before the function’s actual declaration.

Let’s see function overloads in action with our example:

function flipType(arg: string): number;
function flipType(arg: number): string;
function flipType(arg: number | string) {
  if (typeof arg === 'string') {
    return 5;
  }
  return 'some string';
}

We have defined two different scenarios by using the function overload syntaxt: if our arg is a string, the return type should be number, and vice versa.

We can now use this function and gain the advantage of knowing the exact type of the returned variable!

Nick Scialli

Nick Scialli is a senior UI engineer at Microsoft.

© 2024 Nick Scialli