Define a Function with multiple return Types in TypeScript

avatar

Borislav Hadzhiev

Thu Mar 03 20223 min read

banner

Photo by Nathan Dumlao

Define a Function with multiple return Types in TypeScript #

Use a union type to define a function with multiple return types in TypeScript, e.g. function getValue(num: number): string | number {}. The function must return a value that is represented in the union type, otherwise the type checker throws an error.

index.ts
function getValue(num: number): string | number { if (num > 5) { return 100; } return 'hello'; } // 👇️ const result1: string | number const result = getValue(4); if (typeof result === 'string') { // 👇️ result is a string here console.log(result.toUpperCase()); } else { // 👇️ result is a number here console.log(result.toFixed(2)); }

We used a union type to set the return type of a function with multiple return types.

You can use the same approach when working with arrow functions.

index.ts
const getValue = (num: number): string | number => { if (num > 5) { return 100; } return 'hello'; };
A union type is a type formed from combining two or more other types, representing values that may be any one of the specified types.

You can include as many types as necessary in your union. Simply separate the types with a pipe |.

index.ts
const getValue = (num: number): string | number | boolean => { if (num === 0) { return true; } if (num > 5) { return 100; } return 'hello'; };

The function in the example above returns a string or number.

The same approach can be used with type aliases, interfaces or classes.

index.ts
class Animal { run() { console.log('the animal runs'); } } class Human { walk() { console.log('the human walks'); } } function getValue(num: number): Animal | Human { if (num > 5) { const animal = new Animal(); return animal; } const human = new Human(); return human; }

Here is an example of a function that returns a string array or a number array.

index.ts
function getValue(num: number): string[] | number[] { if (num > 5) { return [100]; } return ['hello']; }

Because the functions in the examples have multiple return types, we have to use a type guard before accessing type-specific methods or properties.

index.ts
function getValue(num: number): string | number { if (num > 5) { return 100; } return 'hello'; } // 👇️ const result1: string | number const result = getValue(4); if (typeof result === 'string') { // 👇️ result is a string here console.log(result.toUpperCase()); } else { // 👇️ result is a number here console.log(result.toFixed(2)); }

The result variable stores a string or number, so TypeScript won't allow us to access a string-specific built-in method like toUpperCase until we can narrow the type down.

The type of the value stored in result is a string in the if block.

Because the function returns only 2 possible types, TypeScript knows that the type of the value is a number in the else block.

How you narrow the type down might be different depending on the type of the values the function returns.

For example, if you had to check for an array, you would use Array.isArray(myArray) and if you had to check if a value is an instance of a specific class you would use myInstance instanceof myClass.

A quick and dirty way to get around having to check the type is to use a type assertion.

index.ts
function getValue(num: number): string | number { if (num > 5) { return 100; } return 'hello'; } // 👇️ const result1: string const result = getValue(4) as string; // 👈️ type assertion console.log(result.toUpperCase()); // 👉️ "HELLO"

The as keyword is a type assertion and sets the type of the result variable to a string, without us having to use a type guard.

This approach should generally be avoided as it isn't type safe and would cause a runtime error if the result variable stored a number.

Use the search field on my Home Page to filter through my more than 1,000 articles.