Wat is het recordtype in typoscript?

Wat betekent Record<K, T>in Typescript?

Typescript 2.1 introduceerde het type Recorden beschrijft het in een voorbeeld:

// For every properties K of type T, transform it to U
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>

zie Typescript 2.1

En de pagina Geavanceerde typenvermeldt Recordonder de kop Toegewezen typen naast Readonly, Partialen Pick, in wat de definitie lijkt te zijn:

type Record<K extends string, T> = {
    [P in K]: T;
}

Alleen-lezen, Gedeeltelijk en Kies zijn homomorf, terwijl Record dat niet is. Een aanwijzing dat Record niet homomorf is, is dat er geen invoertype nodig is om eigenschappen te kopiëren van:

type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>

En dat is het. Naast de bovenstaande citaten is er geen andere vermelding van Recordop typescriptlang.org.

Vragen

  1. Kan iemand een eenvoudige definitie geven van wat Recordis?

  2. Is Record<K,T>slechts een manier om te zeggen “alle eigenschappen van dit object hebben het type T“? Waarschijnlijk niet alleeigenschappen, aangezien Keen doel heeft…

  3. Verbiedt de generieke Kextra sleutels op het object die geen Kzijn, of staat het ze toe en geeft het alleen aan dat hun eigenschappen niet worden omgezet in T?

  4. Met het gegeven voorbeeld:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    

    Is het precies hetzelfde als dit?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    

Antwoord 1, autoriteit 100%

  1. Kan iemand een eenvoudige definitie geven van wat Recordis?

Een Record<K, T>is een objecttype waarvan de eigenschapssleutels Kzijn en waarvan de eigenschapswaarden Tzijn. Dat wil zeggen, keyof Record<K, T>is gelijk aan K, en Record<K, T>[K]is (in principe) gelijk aan T.

  1. Is Record<K,T>slechts een manier om te zeggen “alle eigenschappen van dit object hebben het type T“? Waarschijnlijk niet alle objecten, aangezien Keen bepaald doel heeft…

Zoals je opmerkt, heeft Keen doel… om de eigenschapssleutels te beperken tot bepaalde waarden. Als je alle mogelijke sleutels met stringwaarde wilt accepteren, kun je zoiets doen als Record<string, T>, maar de idiomatische manier om dat te doen is door een indexhandtekeningzoals { [k: string]: T }.

  1. Verbiedt de algemene Kextra sleutels op het object die geen Kzijn, of staat het ze toe en geeft het alleen aan dat hun eigenschappen niet worden omgezet in T?

Het “verboden” extra sleutels niet echt: een waarde mag over het algemeen eigenschappen hebben die niet expliciet in het type worden vermeld… maar het zou niet herkennen dat dergelijke eigenschappen bestaan:

declare const x: Record<"a", string>;
x.b; // error, Property 'b' does not exist on type 'Record<"a", string>'

en het zou ze behandelen als overtollige eigenschappendie soms worden afgewezen:

declare function acceptR(x: Record<"a", string>): void;
acceptR({a: "hey", b: "you"}); // error, Object literal may only specify known properties

en soms geaccepteerd:

const y = {a: "hey", b: "you"};
acceptR(y); // okay
  1. Met het gegeven voorbeeld:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    

    Is het precies hetzelfde als dit?:

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    

Ja!

Ik hoop dat dat helpt. Veel succes!


Antwoord 2, autoriteit 37%

Met een record kun je een nieuw type maken van een Union. De waarden in de Union worden gebruikt als attributen van het nieuwe type.

Stel bijvoorbeeld dat ik een vakbond heb zoals deze:

type CatNames = "miffy" | "boris" | "mordred";

Nu wil ik een object maken dat informatie over alle katten bevat, ik kan een nieuw type maken met de waarden in de CatName Union als sleutels.

type CatList = Record<CatNames, {age: number}>

Als ik aan deze CatList wil voldoen, moet ik een object als volgt maken:

const cats:CatList = {
  miffy: { age:99 },
  boris: { age:16 },
  mordred: { age:600 }
}

U krijgt een zeer sterke typeveiligheid:

  • Als ik een kat vergeet, krijg ik een foutmelding.
  • Als ik een kat toevoeg die niet is toegestaan, krijg ik een foutmelding.
  • Als ik CatNames later verander, krijg ik een foutmelding. Dit is vooral handig omdat CatNames waarschijnlijk uit een ander bestand wordt geïmporteerd en waarschijnlijk op veel plaatsen wordt gebruikt.

React voorbeeld uit de echte wereld.

Ik heb dit onlangs gebruikt om een Status-component te maken. Het onderdeel zou een statusprop krijgen en vervolgens een pictogram weergeven. Ik heb de code hier behoorlijk vereenvoudigd voor illustratieve doeleinden

Ik had een vakbond als deze:

type Statuses = "failed" | "complete";

Ik heb dit gebruikt om een object als dit te maken:

const icons: Record<
  Statuses,
  { iconType: IconTypes; iconColor: IconColors }
> = {
  failed: {
    iconType: "warning",
    iconColor: "red"
  },
  complete: {
    iconType: "check",
    iconColor: "green"
  };

Ik zou dan kunnen renderen door een element van het object in rekwisieten te destructureren, zoals:

const Status = ({status}) => <Icon {...icons[status]} />

Als de Statuss-unie later wordt uitgebreid of gewijzigd, weet ik dat mijn Status-component niet kan worden gecompileerd en krijg ik een foutmelding die ik onmiddellijk kan oplossen. Hierdoor kan ik extra foutstatussen aan de app toevoegen.

Houd er rekening mee dat de daadwerkelijke app tientallen foutstatussen had waarnaar op meerdere plaatsen werd verwezen, dus dit type beveiliging was buitengewoon nuttig.

Other episodes