Return Multiple values from a Function in TypeScript

avatar
Borislav Hadzhiev

Last updated: Feb 27, 2024
5 min

banner

# Table of Contents

  1. Return Multiple values from a Function in TypeScript
  2. Define a Function with multiple return Types in TypeScript

# Return Multiple values from a Function in TypeScript

To return multiple values from a function in TypeScript, group the values in an array and return the array, e.g. return [myValue1, myValue2] as const.

You can then destructure and use the values the function returns.

index.ts
function getValues() { const str = 'bobbyhadz.com'; const num = 100; return [str, num] as const; } // ๐Ÿ‘‡๏ธ const result: readonly ["bobbyhadz.com", 100] const result = getValues(); const [str, num] = getValues(); console.log(str.toUpperCase()); // ๐Ÿ‘‰๏ธ "BOBBYHADZ.COM" console.log(num.toFixed(2)); // 100.00

return multiple values from function

The code for this article is available on GitHub

If you need to define a function with multiple return types, click on the following subheading:

We declared a function that returns multiple values by grouping them in an array.

Notice that the type of the result variable (and the function's return type) is ["bobbyhadz.com", 100].

The as const syntax is called a const assertion in TypeScript.

The const assertion sets the function's return type to be readonly ["bobbyhadz.com", 100], which is exactly what we want.

We want the values to be typed correctly when we destructure them from the function's return value.

Let's look at the function's return type if we omit the const assertion.

index.ts
function getValues() { const str = 'bobbyhadz.com'; const num = 100; return [str, num]; } // ๐Ÿ‘‡๏ธ const result: (string | number)[] const result = getValues(); const [str, num] = getValues(); // ๐Ÿ‘‡๏ธ Now str is string or number // and num is `string` or `number`

Without the as const syntax, the function is typed to return an array containing strings or numbers.

This isn't great, because when we destructure the values from the array into the str and num variables, they are typed as string | number.

The string | number syntax is called a union type in TypeScript. A union type is formed by combining two or more other types.

I've written a detailed article on how to define an array with multiple types in TS.

# Using a tuple return type instead

You could get around this by explicitly setting the function's return type to a tuple containing a string and a number.

index.ts
function getValues(): [string, number] { const str = 'bobbyhadz.com'; const num = 100; return [str, num]; } // ๐Ÿ‘‡๏ธ const result: [string, number] const result = getValues(); const [str, num] = getValues();

using tuple return type instead

The code for this article is available on GitHub

We've explicitly typed the function to return a tuple where the first element is a string and the second is a number.

Now when we destructure the values into the str and num variables, they are typed correctly.

The syntax with the square brackets on the left-hand side of the assignment is called destructuring.

index.ts
const [a, b] = ['bobby', 'hadz']; console.log(a); // ๐Ÿ‘‰๏ธ "bobby" console.log(b); // ๐Ÿ‘‰๏ธ "hadz"

An easy way to think about it is that we are assigning the elements of the array to variables. Note that the order of assignment and the order of the values in the array is the same.

If you don't want to use destructuring, you can explicitly access the values by using bracket notation.

index.ts
function getValues() { const str = 'bobbyhadz.com'; const num = 100; return [str, num] as const; } // ๐Ÿ‘‡๏ธ const result: [string, number] const result = getValues(); const str = result[0]; const num = result[1];

# Define a Function with multiple return Types in TypeScript

Use a union type to define a function with multiple return types in TypeScript.

index.ts
function getValue(num: number): string | number { if (num > 5) { return 100; } return 'bobbyhadz.com'; } // ๐Ÿ‘‡๏ธ 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)); }

defining function with multiple return types

The code for this article is available on GitHub

The function must return a value that is represented in the union type, otherwise, the type checker throws an error.

# Using arrow functions

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 'bobbyhadz.com'; };
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 'bobbyhadz.com'; };

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

# Using classes, type aliases or interfaces

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; }
The code for this article is available on GitHub

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

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

# Use a type guard before accessing properties

The functions in the examples have multiple return types, so 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 'bobbyhadz.com'; } // ๐Ÿ‘‡๏ธ 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 a 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.

The function returns only 2 possible types, so 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'd use Array.isArray(myArray) and if you had to check if a value is an instance of a specific class, you'd use myInstance instanceof myClass.

# Using a type assertion

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 'bobbyhadz.com'; } // ๐Ÿ‘‡๏ธ const result1: string const result = getValue(4) as string; // ๐Ÿ‘ˆ๏ธ type assertion console.log(result.toUpperCase()); // ๐Ÿ‘‰๏ธ "bobbyhadz.com"

The as keyword is a type assertion and sets the type of the result variable to 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.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev