typescript - Hvorfor er et tall en gyldig nøkkel for `{ [key: string]: unknown; }`?


function Foo<DataType extends { [_: string]: unknown }>(name: keyof DataType) {
  return name;
}

Foo<{"name":"Tom",1:string}>(1);   // why is this not an error?

Hva skjedde her? Jeg tror en talltast skal være en feil.

Svar #1

TypeScript behandler omtrent numeriske nøkler som en spesiell type strengenøkkel.

Det er fordi i JavaScript blir alle ikke-symbol-egenskapsnøkler tvunget til string. I TypeScript-dokumentasjonen for indeks-signaturer refereres det til dette på en noe indirekte måte ved å nevne at en number-indeks-signatur-egenskapstype må være kompatibel med en string-indeks-signatur:

Det er mulig å støtte begge typer indekser, men typen som returneres fra en numerisk indeks må være en undertype av typen som returneres fra strengeindeksen. Dette er fordi når man indekserer med et number, vil JavaScript faktisk konvertere det til en string før indeksering i et objekt. Det betyr at indeksering med 100 (et number) er det samme som å indeksere med "100" (en string), så de to må være konsistente.

Faktisk, fra og med TypeScript 2.9, vil keyof-operatoren når den brukes på en type med en string-indeks-signatur returnere number så vel som string:

type X = keyof { [_: string]: unknown };
// type X = string | number

Dette er ikke helt nøyaktig eller konsekvent, og det finnes noen merkelige spesialtilfeller andre steder i språket ("1" extends keyof {1: string} er falsk, og det er også 1 extends keyof {"1": string}, men du kan likevel få tilgang til begge nøklene på et objekt av begge typene:

let k1: keyof { 1: string };
k1 = 1; // okay
k1 = "1"; // error
declare const o1: { 1: string };
o1[1]; // okay
o1["1"]; // okay

let k2: keyof { "1": string };
k2 = 1; // error
k2 = "1"; // error
declare const o2: { "1": string };
o2[1]; // okay
o2["1"]; // okay

Men det er sekundære effekter. Hvis du må avvise numeriske nøkler av en eller annen grunn, kan du se på spørsmålet og svaret på Forbid number property for string-typed index signature.

Lenke til kode på lekeplassen

Svar #2

Den godtar ikke noe tall, bare 1:

Foo<{"name":"Tom",1:string}>(2); // will give an error

Lekeplass

Dessuten er typen TypeScript utleder fra objektet ditt "name" | 1:

type Key = keyof {"name":"Tom",1:string}
//   ^? type Key = "name" | 1

Typescript-håndboken indikerer at string, number, symbol, malstrenglignende mønstre og unionstyper som kun består av disse, er tillatt som nøkler.

Relaterte artikler