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 a length of 2, with a number at element 0 and a string at element 1.
Why then, does TypeScript allow you to call methods like push(), pop(), shift(), unshift(), and splice() 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.
There have been some newer issues referencing microsoft/TypeScript#6325 asking to reconsider this now that tuples have gotten a little more strict in the intervening time. See microsoft/TypeScript#40316 and microsoft/TypeScript#48465, which are open but not obviously popular. 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
let testArray:[number, string];behave? It's undefined upon declaration.