Home > Mobile >  Readonly spread array in tuple
Readonly spread array in tuple

Time:05-09

I have some TypeScript code that I mean not to be executed, but it does, why?

let a:[boolean, ... readonly string[]] = [true, '1', '2', '3'];

a[0] = false;
a[1] = 'one'; //no error, but it should be error

CodePudding user response:

The reason your code doesn't produce an error is that the type of a is immediately reduced by the compiler to the fully-mutable type [boolean, ...string[]], despite your annotation:

let a: [boolean, ... readonly string[]] = [true, '1', '2', '3'];

type A = typeof a;
// type A = [boolean, ...string[]]

And therefore none of the elements of a are read-only. So that's the answer to the question as asked.


The obvious follow-up question is "why does it get reduced to a fully mutable type?". Unfortunately I can't find any authoritative source for this, so anything I could say here would be speculation. Here it comes:

The type [T, ...A] is the type you get when you spread an array of type A into the end of an array literal that starts with a value of type t. The fact that the following function compiles with no error is evidence of this:

function f<T, A extends readonly any[]>(t: T, a: A): [T, ...A] {
    return [t, ...a]
}

And if I have a read-only string array and spread it to the end of an array literal, the resulting array will not be read-only:

const strs: readonly string[] = ["x", "y"]
const result = f(true, strs);
// const result: [boolean, ...string[]]

So that's my guess. If anyone finds any canonical source (e.g., TS doc or GitHub issue) that confirms or refutes this, I'd be interested to know about it.

Playground link to code

CodePudding user response:

Spreading an array/tuple just orderly lists out the element of that array.

It just plucks out the values from the array without actually modifying/transferring the inferred characteristics

let xs = [1,2,3,4]

let ys = [...xs] // [1,2,3,4]

Hence when we do

let a:[boolean, ... readonly string[]] = [true, '1', '2', '3'];

We are just saying pluck all the values from the readonly string array and not that make the values as readonly.

Thus the behavior.

CodePudding user response:

It works because readonly is only the individual elements themselves. The array itself is still mutable.

If you did

let a:readonly [boolean, ... readonly string[]] = [true, '1', '2', '3'];

a[0] = false; // error
a[1] = 'one'; //error

then, yes, it errors because you've marked the array itself as readonly, not just some of its values.

  • Related