XCS
XCS

Reputation: 28177

TypeScript return immutable/const/readonly Array

I want to have a function which returns an Array, but I want the returned Array to be readonly, so I should get a warning/error when I try to change its contents.

function getList(): readonly number[] {
   return [1,2,3];
}


const list = getList();
list[2] = 5; // This should result in a compile error, the returned list should never be changed

Can this be achieved in TypeScript?

Upvotes: 40

Views: 30637

Answers (6)

SirRandomName
SirRandomName

Reputation: 1

Other option is as const keyword.

"as const declares the content of a variable or constant as readonly and makes sure that the contents of the variable or constant are not changed" (src)

function getList() {
  return [1,2,3] as const
}

const list = getList();
list[2] = 5; // error

error: Cannot assign to '2' because it is a read-only property.

result what your ide will show:

function getList(): readonly [1, 2, 3]

pro: is it clean (no need to define return type manually or create new type)

con: not explicit

Upvotes: 0

Ruochen Jia
Ruochen Jia

Reputation: 9

You can use Object.freeze to return a readonly array without using any type annotations:

function getList() {
  return Object.freeze([1,2,3]);
}

const list = getList();
list[2] = 5; // error

console.log(list);

Upvotes: 1

Borek Bernard
Borek Bernard

Reputation: 53352

The very code from OP now works since TypeScript 3.4 introduced a new syntax for ReadonlyArray:

While it's good practice to use ReadonlyArray over Array when no mutation is intended, it's often been a pain given that arrays have a nicer syntax. Specifically, number[] is a shorthand version of Array<number>, just as Date[] is a shorthand for Array<Date>.

TypeScript 3.4 introduces a new syntax for ReadonlyArray using a new readonly modifier for array types.

This code now works as expected:

function getList(): readonly number[] {
   return [1,2,3];
}

const list = getList();
list[2] = 5; // <-- error

Playground.

Upvotes: 37

Matthew Layton
Matthew Layton

Reputation: 42390

This seems to work...

function getList(): ReadonlyArray<number> {
    return [1, 2, 3];
}

const list = getList();

list[0] = 3; // Index signature in type 'ReadonlyArray<number>' only permits reading.

Try it in the Playground

ReadonlyArray<T> is implemented like this:

interface ReadonlyArray<T> {
    readonly [n: number]: T;
    // Rest of the interface removed for brevity.
}

Upvotes: 38

Avraam Mavridis
Avraam Mavridis

Reputation: 8940

The following will make the list readonly but the items in it not:

function getList(): Readonly<number[]> {
   return [1,2,3];
}

let list = getList();
list = 10; // error
list[1] = 5 // that is fine

And this one will make the list and the items of it readonly:

function getList(): ReadonlyArray<number> {
   return [1,2,3];
}

let list = getList();
list = 10; // error
list[1] = 5 // error as well

Upvotes: 6

millimoose
millimoose

Reputation: 39990

TypeScript has a ReadonlyArray<T> type that does this:

TypeScript comes with a ReadonlyArray type that is the same as Array with all mutating methods removed, so you can make sure you don’t change your arrays after creation

function getList(): ReadonlyArray<number> {
   return [1,2,3];
}

const list = getList();
list[2] = 5; // error

for (const n of list) {
    console.log(n);
}

Upvotes: 1

Related Questions