Declare functions returning Object or Array in TypeScript

avatar
Borislav Hadzhiev

Last updated: Feb 27, 2024
9 min

banner

# Table of Contents

  1. Declare a function with an Object return type in TypeScript
  2. Declare a function with an Array return type in TypeScript
  3. Declare a function with a Tuple return type in TypeScript
  4. Declare a function with a Readonly return type in TypeScript

# Declare a function with an Object return type in TypeScript

To declare a function with an object return type, set the return type of the function to an object right after the function's parameter list.

If the return type of the function is not set, TypeScript will infer it.

index.ts
// ✅ named function function getObj(): { name: string; age: number } { return { name: 'Bobby Hadz', age: 30 }; } // ✅ arrow function const getObj2 = (): { name: string; age: number } => { return { name: 'Bobby Hadz', age: 30 }; };

declare function with object return type

The code for this article is available on GitHub

Here are two more examples.

index.ts
// ✅ class method class A { getObj(): { name: string; age: number } { return { name: 'Bobby Hadz', age: 30 }; } } // ✅ Using interface interface Person { name: string; age: number; } function getObj3(): Person { return { name: 'Bobby Hadz', age: 30 }; }

You can set the return type of a function right after its parameter list.

index.ts
interface Person { name: string; age: number; } function getObj4(name: string, age: number): Person { return { name, age }; }

The examples show how to set the return type of a function to an object that contains name and age properties.

The advantage of setting the return type of the function explicitly is that the type checker would throw an error if you try to return an object of a different type.

index.ts
interface Person { name: string; age: number; } function getObj3(): Person { // ⛔️ Error: Object literal may only // specify known properties, and 'country' // does not exist in type 'Person'.ts(2322) return { name: 'Bobby', age: 30, country: 'Chile' }; }

If you don't explicitly set the return type of the function, TypeScript will infer it.

index.ts
// 👇️ function getObj3(): {name: string; age: number; country: string;} function getObj3() { return { name: 'Bobby Hadz', age: 30, country: 'Chile' }; }
When setting the return type of a function to an object, you might not know all of the properties the object will have.

# Declare a function with an Object return type using an index signature

If that's the case, you can use an index signature.

index.ts
interface Person { name: string; age: number; [key: string]: any; // 👈️ index signature } function getObj3(): Person { return { name: 'Bobby Hadz', age: 30, country: 'Chile', city: 'Santiago', }; }

declare function with object return type using index signature

The code for this article is available on GitHub

An index signature is used when we don't know all of the names of a type's properties and the type of its values ahead of time.

The index signature in the examples means that when the object is indexed with a string, it will return a value of any type.

You might also see the index signature {[key: string]: string} in examples. It represents a key-value structure that when indexed with a string returns a value of type string.

We still get type safety for the properties that we know about in advance.

For example, the name and age properties have to exist on the object the function returns and have to be of a specific type.

If you try to omit the properties or set them to an incorrect type, you'll get an error.

index.ts
interface Person { name: string; age: number; [key: string]: any; } function getObj3(): Person { // ⛔️ Error: Type 'number' is not assignable // to type 'string'.ts(2322) return { name: 100, age: 30, country: 'Chile', city: 'Santiago' }; }

We passed a number for the name property, so the type checker threw an error.

You should only use this approach when you don't know the names of all of the object's keys ahead of time.

It's always best to be as explicit as possible and write the most type-safe code.

# Table of Contents

  1. Declare a function with an Array return type in TypeScript
  2. Declare a function with a Tuple return type in TypeScript
  3. Declare a function with a Readonly return type in TypeScript

# Declare a function with an Array return type in TypeScript

To declare a function with an array return type, set the return type of the function to an array right after the function's parameter list.

index.ts
// ✅ Named function returning an array of strings function getArr(): string[] { return ['bobby', 'hadz', 'com']; } // ✅ Arrow function returning an array of numbers const getArr2 = (): number[] => { return [1, 2, 3]; };

declare function with array return type

The code for this article is available on GitHub

Here are 2 more examples.

index.ts
// ✅ Class method returning an array of objects class A { getArr(): { id: number; name: string }[] { return [{ id: 1, name: 'Bobby Hadz' }]; } } // ✅ Using type as Person[] for function's return value type Person = { name: string; age: number; }; function getArr3(): Person[] { return [{ name: 'Bobby Hadz', age: 30 }]; }

You can set the return type of a function right after its parameter list.

index.ts
type Person = { name: string; age: number; }; function getArr3(name: string, age: number): Person[] { return [{ name, age }]; }

The examples above show how to set the return type of a function to an array containing different values.

The advantage of setting the return type of the function explicitly is that the type checker would throw an error if you try to return an array of a different type.

index.ts
function getArr(): string[] { // ⛔️ Error: Type 'number' is not assignable to type 'string'.ts(2322) return [1, 2, 3]; }

If you don't explicitly set the return type of the function, TypeScript will infer it.

index.ts
// 👇️ function getArr(): string[] function getArr() { return ['bobby', 'hadz', 'com']; }

# Use a union to type functions returning mixed-type arrays

If your function returns an array of mixed types, e.g. strings and numbers, you have to use a union to specify the function's return type.

index.ts
function getArr(): (string | number)[] { return ['bobby', 1, 'hadz', 2]; }
The code for this article is available on GitHub

The function above returns an array that contains strings and numbers. Notice that we used parentheses to wrap the values - (string | number)[] and not string | number[].

# Function returning an array of objects in TypeScript

If your function returns an array of objects, create a type or an interface and set the function's return type as Type[].

index.ts
type Person = { name: string; age: number; }; function getArr3(name: string, age: number): Person[] { return [{ name, age }]; }

The function returns an array of objects that contain the name and age properties.

Sometimes when you return an array of objects, you might now know all of the properties an object might have ahead of time.

# Using an index signature to type a function returning an array of objects

If that's the case, you can use an index signature.

index.ts
type Person = { name: string; age: number; [key: string]: any; // 👈️ index signature }; function getArr3(name: string, age: number): Person[] { return [{ name, age, city: 'Santiago' }]; }
The code for this article is available on GitHub

An index signature is used when we don't know all of the names of a type's properties and the type of its values ahead of time.

The index signature in the examples means that when the object is indexed with a string, it will return a value of any type.

You might also see the index signature {[key: string]: string} in examples. It represents a key-value structure that when indexed with a string returns a value of type string.

We still get type safety for the properties that we know about in advance.

For example, the name and age properties have to be set and be of a specific type.

If you try to omit the properties or set them to an incorrect type, you'll get an error.

index.ts
type Person = { name: string; age: number; [key: string]: any; // 👈️ index signature }; function getArr3(): Person[] { // ⛔️ Error: Type 'boolean' is not // assignable to type 'string'.ts(2322) return [{ name: true, age: 30, city: 'Santiago' }]; }

We passed a boolean for the name property, so the type checker threw an error.

It's always best to be as explicit as possible and write the most type-safe code.

# Table of Contents

  1. Declare a function with a Tuple return type in TypeScript
  2. Declare a function with a Readonly return type in TypeScript

# Declare a function with a Tuple return type in TypeScript

To declare a function with a tuple return type, set the return type of the function to a tuple right after the function's parameter list.

If the return type of the function is not set, TypeScript will infer it as type[].

index.ts
// ✅ Named function returning a tuple function getTuple(): [number, number] { return [5, 10]; } // ✅ Arrow function returning a tuple const getTuple2 = (): [string, string] => { return ['bobby', 'hadz']; }; // ✅ Using a type type Numbers = [number, number]; function getTuple4(): Numbers { return [10, 10]; }
The code for this article is available on GitHub

You can set the return type of a function right after its parameter list.

To set the return type of a function to a tuple, pass the types of the tuple between square brackets as if passing elements to an array.

index.ts
function getTuple(a: number, b: number): [number, number] { return [a, b]; }

The examples show how to set the return type of a function to a tuple containing different values.

The advantage of setting the return type of the function explicitly is that the type checker would throw an error if you try to return a tuple of a different type.

index.ts
function getTuple(): [number, number] { // ⛔️ Error: Type '[number, number, number]' // is not assignable to type '[number, number]' return [10, 100, 1000]; }

If you don't explicitly set the return type of the function, TypeScript will infer it to be number[] instead of [number, number].

index.ts
// 👇️ function getTuple(): number[] function getTuple() { return [10, 100]; }

You might also see a const assertion being used in a similar way to how we typed the return value of the function.

index.ts
// 👇️ function getTuple3(): readonly [10, 10] function getTuple3() { return [10, 10] as const; }

The function in the example returns a readonly array containing 2 numbers with a value of 10.

There are a couple of differences between the two approaches.

If you don't explicitly set the type as readonly or use a const assertion, it can still be mutated.

index.ts
function getTuple(): [number, number] { return [10, 100]; } const t = getTuple(); t.push(1000); console.log(t); // 👉️ [10, 100, 1000]

If you want to use this approach but want the tuple to be read-only, pass the return type of the function to the Readonly utility type.

index.ts
function getTuple(): Readonly<[number, number]> { return [10, 100]; } const t = getTuple(); // ⛔️ Error: Property 'push' does not // exist on type 'readonly [number, number]'.ts(2339) t.push(1000);

The Readonly utility type constructs a type with all properties set to readonly.

# Declare a function with a Readonly return type in TypeScript

Use the Readonly utility type to declare a function with a read-only return type.

The Readonly utility type constructs a type with all properties set to readonly. The properties of the constructed type cannot be reassigned.

index.ts
function getArr(): Readonly<string[]> { return ['bobby', 'hadz', 'com']; } function getObj(): Readonly<{ name: string }> { return { name: 'Bobby Hadz' }; }
The code for this article is available on GitHub

Here are 2 more examples.

index.ts
function getSet(): ReadonlySet<string> { return new Set(['bobby', 'hadz', 'com']); } function getMap(): ReadonlyMap<string, string> { return new Map([['name', 'Bobby Hadz']]); }

We used the Readonly utility type to type a function whose return value only permits reading.

You can set the return type of a function right after its parameter list.

The 2 functions in the following code snippet have the same return type - a readonly array of strings.

index.ts
function getArr(): Readonly<string[]> { return ['bobby', 'hadz', 'com']; } function getArr2(): ReadonlyArray<string> { return ['a', 'b', 'c']; }

If you try to change a value in the readonly array, you'd get an error.

index.ts
function getArr(): Readonly<string[]> { return ['bobby', 'hadz', 'com']; } const a = getArr(); // ⛔️ Index signature in type 'readonly string[]' // only permits reading.ts(2542) a[0] = 'z';

The same is the case when working with read-only objects.

index.ts
function getObj(): Readonly<{ name: string }> { return { name: 'Bobby Hadz' }; } const obj = getObj(); // ⛔️ Error: Property 'age' does not exist // on type 'Readonly<{ name: string; }>'.ts(2339) obj.age = 30;

When working with Set or Map objects, make sure to use the corresponding utility types - ReadonlySet and ReadonlyMap.

index.ts
function getSet(): ReadonlySet<string> { return new Set(['bobby', 'hadz', 'com']); } function getMap(): ReadonlyMap<string, string> { return new Map([['name', 'Bobby Hadz']]); }

The first type we passed to the ReadonlyMap utility type is the type for the keys, and the second - for the values.

If you need to pass a function as a parameter, check out the following article.

# 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.