javascript - Hvorfor 1 utvider {[Key: string]: never} er falsk


Jeg er veldig forvirret over dette, hvorfor 1 extends {[Key: string]: never} er falsk. For eksempel:

type T = 1 extends {[Key: string]: never} ? true : false;

Hvorfor T returnerer false.

Svar #1

En type av formen {[key: string]: XXX} har en string indeks-signatur. En verdi av en slik type kan ha et hvilket som helst antall (inkludert null) medlemmer med streng-nøkler (medlemmer er egenskaper, som inkluderer metoder, og inkluderer arvede egenskaper); og alle medlemmer med streng-nøkler som den har, må være av typen XXX:

let dict: { [key: string]: string };
dict = { a: "hello", b: "goodbye" }; // okay
dict = { a: "hello", b: 123 }; // error!
// ----------------> ~ 
// Type 'number' is not assignable to type 'string'.
dict = {} // okay

Typeen never er TypeScripts grunnleggende type; det finnes ingen verdier av typen never. Den er for typer det tomme settet er for mengder. Uansett hvilken verdi du har, vil den ikke være av typen never. Du skal ikke kunne observere en verdi av typen never.

Når man setter disse sammen, kan en verdi av typen {[key: string]: never} ha et hvilket som helst antall medlemmer med strengnøkler (inkludert null), og alle medlemmer med strengnøkler den har må være av typen never. Men siden ingen verdi er av typen never, betyr det at en verdi av typen {[key: string]: never} må ha nøyaktig null medlemmer med strengnøkler:

let neverDict: { [key: string]: never };
neverDict = { a: "hello", b: "goodbye" }; // error!
// ---------> ~  -------> ~
// Type 'string' is not assignable to type 'never'.

dict = {} // okay

Eller i det minste må alle medlemmer med strengnøkler som er til stede, forventes å være uobserverbare:

function error(): never { throw new Error(); }
function special() {
  dict = { a: error() } // okay
}

Her tilordner vi en verdi av typen {a: never} til dict, noe som er greit, men merk at hvis du noen gang prøvde å kjøre programmet for å se på en slik verdi, ville det være uobserverbart fordi en feil vil bli kastet.

Så, for å kunne tildeles {[key: string]: never}, må en type ikke ha medlemmer med strengnøkkel.


På den annen side har vi typen 1. Dette er en numerisk literaltype som er en underkategori av number. Hver verdi av typen 1 er også en verdi av typen number. Videre er number en underkategori av Number, grensesnittet for innpakningsobjektet som number-verdier får når du indekserer dem som objekter.

Her er definisjonen av Number-grensesnittet fra TypeScript-standardbiblioteket:

interface Number {
    toString(radix?: number): string;
    toFixed(fractionDigits?: number): string;
    toExponential(fractionDigits?: number): string;
    toPrecision(precision?: number): string;
    valueOf(): number;
}

Merk at alle primitive verdier i JavaScript, bortsett fra null og undefined, har slike wrapper-objekter, og derfor kan disse primitive verdiene tilordnes til grensesnitt og er dermed "objekt-lignende" i deres behandling av TypeScript.

Så, 1 er en underkategori av number, som er en underkategori av Number, som har noen kjente medlemmer som vist ovenfor:

let one: 1 = 1;
let prim: number = 1;
let intf: Number = prim;

(1).toFixed // (method) Number.toFixed(fractionDigits?: number | undefined): string

Og nå kan vi se at 1 ikke skal kunne tilordnes til {[key: string]: never}. Den førstnevnte har flere medlemmer med nøkler som "toFixed" og "toExponential", og disse medlemmene har verdier av funksjonstyper. Funksjoner er faktiske verdier som ikke kan tilordnes til never. Så dette er en feil:

neverDict = one; // error!
// Type 'number' is not assignable to type '{ [key: string]: never; }'.

Og derfor er 1 extends {[key: string]: never} usant, og dermed tar den betingede typen du skrev den falske grenen:

type T = 1 extends { [key: string]: never } ? true : false;
// type T = false

Lenke til kode på lekeplassen

Svar #2

Jeg var forvirret over det samme fenomenet:

type test1 = 1 extends {} ? true : false // true

Så, jeg antar, når man sammenligner originaltypen med objektet, skjer det en implisitt typekonvertering akkurat som i koden nedenfor:

type test2 = {
  [key in keyof 1]: 1[key]
}
/**
  type test2 = {
    toString: (radix?: number | undefined) => string;
    toFixed: (fractionDigits?: number | undefined) => string;
    toExponential: (fractionDigits?: number | undefined) => string;
    toPrecision: (precision?: number | undefined) => string;
    valueOf: () => number;
    toLocaleString: (locales?: string | ... 1 more ... | undefined, options?: Intl.NumberFormatOptions | undefined) => string;
  }
 */

det er i konflikt med {[Key: string]: aldri}

Relaterte artikler