javascript - Typescript array push-metoden kan ikke fange en tuppeltype av arrayen


const testArray:[number, string] = [10, 'test', 's'];

Det fungerer ikke.

const testArray:[number, string] = [10, 'test']; // It's been edited.
testArray.push('test');

Det fungerer.

Jeg tror den andre koden ikke skulle fungert.
Hvorfor fungerer den andre koden? Er det en feil?


-Lagt til-

Jeg har tenkt på problemet.
Kompilatoren kan bare fange feil under kompilering. Så kompilatoren fanger ikke feilen. Er det riktig?

Svar #1

Dette er et godt spørsmål, og jeg vil prøve å omformulere det så eksplisitt som mulig:

Tuplete typer er en type matrise med kjent lengde, hvor de forskjellige elementene kan ha forskjellige typer. En verdi av typen [number, string] er garantert å ha en length på 2, med et number på element 0 og en string på element 1.

Hvorfor tillater da TypeScript at du kaller metoder som push(), pop(), shift(), unshift() og splice() på verdier av tupple-typer, når slike metoder generelt ødelegger de antatte garantiene for tupple-typer? Bør det ikke stoppe deg fra å gjøre det, akkurat som det stopper deg fra å tilordne en verdi som [1, "two", "three"] til [number, string] i utgangspunktet?

Ja, det er ikke bra.

Jeg vet ikke om det finnes et godt kanonisk svar på dette. Det nærmeste jeg kan finne er microsoft/TypeScript#6325, som foreslår at slike metoder bør utelates fra tuppeltyper. Dette forslaget ble avslått, muligens på grunn av at det ville være en brytende endring for eksisterende kode i virkelige prosjekter.

Et foreslått alternativ ser slik ut

type StrictTuple<T extends any[]> =
    Omit<T, keyof (any[])> extends infer O ? { [K in keyof O]: O[K] } : never;

som ser mindre ut som et array og mer ut som et sett med numeriske nøkkel-egenskaper:

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; }

Hvis du virkelig bryr deg om slike ting, kan det hende du vil bruke noe som StrictTuple ovenfor, men det er sannsynligvis mer bry enn det er verdt. Tuple-typer er allestedsnærværende i TypeScript, og hvis du bruker en form som ikke kan tildeles dem, må du gjennom mange uheldige hindringer for å bruke TypeScript.

Pragmatisk sett vil jeg si at du bare bør prøve å ikke endre tupler.

Det har vært noen nyere saker som refererer til microsoft/TypeScript#6325 som ber om å vurdere dette på nytt nå som tupler har blitt litt mer strenge i mellomtiden. Se microsoft/TypeScript#40316 og microsoft/TypeScript#48465, som er åpne, men ikke åpenbart populære. Det ville være en interessant øvelse å se hva som spesifikt ville bryte hvis push/pop/osv. ble utelatt fra tuplet-typer.

Lenke til kode på lekeplassen

Svar #2

[Fjernet forrige svar siden jeg misforstod.]

Ser ut som dette kan være et problem relatert til typeutvidelse? Du kan erklære tuplen din som readonly eller as const for å forhindre at push-funksjonen fungerer på tuplen i det hele tatt

const testArray:readonly [number, string] = [10, 'test'] as const;
testArray.push('test') // error

Jeg fant denne Medium-artikkelen om emnet: https://blog.logrocket.com/const-assertions-are-the-killer-new-typescript-feature-b73451f35802/

Relaterte artikler