TypeScript return immutable/const/readonly Array
Asked Answered
I

6

38

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?

Interlope answered 24/4, 2018 at 13:36 Comment(5)
There is one issue with using Readonly<number[]>. I can no longer use for...of, saying that type must have a method that returns an iterator.Interlope
...and it doesn't seem to work. Surely I should be getting an error there?Ingrate
I don't think this is a duplicate exactly. From what I can see, the accepted answer doesn't even work in the other question.Abert
@series0ne: Yeah, see above. I went to try it so I could comment an example (I like to do that with dupes), and...it didn't work. :-)Ingrate
In pure JS you may use a => Object.freeze(a); which turns the a array into shallow immutable. Attempting to change or delete it's items seems throw a "Type Error" in strict mode but fails silenty otherwise. If any one of the items is a reference type then it will remain mutable unless you freeze them i.e. recursively.Einstein
A
37

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.
}
Abert answered 24/4, 2018 at 13:46 Comment(1)
Thank you, this is what I was looking for. I think TypeScript docs are lacking in this direction, didn't too many references to this functionality.Interlope
E
36

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.

Edmond answered 13/9, 2019 at 11:56 Comment(0)
D
5

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
Deadradeadweight answered 24/4, 2018 at 13:53 Comment(0)
P
1

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);
}
Poundal answered 24/4, 2018 at 13:51 Comment(0)
S
1

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);
Salford answered 26/2, 2023 at 22:49 Comment(0)
V
0

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

Vitalis answered 23/8, 2023 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.