const testArray:[number, string] = [10, 'test', 's'];
It doesn't work.
const testArray:[number, string] = [10, 'test']; // It's been edited.
testArray.push('test');
It works.
I think second code shouldn't worked.
Why does the second code work? Is it a bug?
-Added-
I've been thinking about the problem.
Compiler can catch errors only in compile time. So the compiler doesn't catch the error. Is it right?
This is a good question, and I'll try to rephrase it as explicitly as possible:
Tuple types are a type of array of known length and where the different elements may have different types. A value of type
[number, string]
is guaranteed to have alength
of2
, with anumber
at element0
and astring
at element1
.Why then, does TypeScript allow you to call methods like
push()
,pop()
,shift()
,unshift()
, andsplice()
on values of tuple types, when such methods generally destroy the supposed guarantees of tuple types? Shouldn't it stop you from doing that, just like it stops you from assigning a value like[1, "two", "three"]
to[number, string]
in the first place?
Yeah, it's not great.
I don't know that there's a good canonical answer to this. The closest I can find is microsoft/TypeScript#6325, which proposes that such methods be omitted from tuple types. This proposal was declined, on the possible grounds that it would be a breaking change for existing real-world code.
A suggested alternative looks like
type StrictTuple<T extends any[]> =
Omit<T, keyof (any[])> extends infer O ? { [K in keyof O]: O[K] } : never;
which looks less like an array and more like a set of numeric-key properties:
const x: StrictTuple<[number, string]> = [1, ""] // {0: number; 1: string }
x[1] = "okay";
x[0] = 123;
x.push(123); // error!
//~~~~ Property 'push' does not exist on type { 0: number; 1: string; }
If you really care about such things, you might want to use something like StrictTuple
above, but it's probably more trouble than it's worth. Tuple types are ubiquitous in TypeScript and if you use a form that is not assignable to them, then you will have to jump through a lot of unfortunate hoops to use TypeScript.
Pragmatically speaking, I'd say just try not to mutate tuples.
It's possible that someone might open a new issue referencing microsoft/TypeScript#6325 asking to reconsider this now that tuples have gotten a little more strict in the intervening time. It would be an interesting exercise to see what specifically would break if push
/pop
/etc were omitted from tuple types.
Playground link to code
[Removed previous answer since I misinterpreted.]
Looks like this could be an issue related to type widening?
You can declare your tuple to be readonly
or as const
to prevent the push function from working on the tuple at all
const testArray:readonly [number, string] = [10, 'test'] as const;
testArray.push('test') // error
I found this medium article on the topic: https://blog.logrocket.com/const-assertions-are-the-killer-new-typescript-feature-b73451f35802/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With