Kodokon kodokon.com

Mapped Types und Key Remapping: Typen umformen

Verstehe, wie homomorphe Mapped Types Modifikatoren bewahren und wie die as-Klausel Schlüssel umbenennt oder filtert.

8 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Ein Mapped Type iteriert über eine Menge von Schlüsseln, um einen neuen Objekttyp zu erzeugen. Die Form [K in keyof T] heißt homomorph: Der Compiler weiß, dass die Struktur von T stammt, und kopiert automatisch die Modifikatoren readonly und ? jeder ursprünglichen Eigenschaft. Mit den Präfixen + und - fügst du diese Modifikatoren ausdrücklich hinzu oder entfernst sie: Genau das ist die interne Mechanik hinter Partial, Required und Readonly.

TYPESCRIPT
type Mutable<T> = {
  -readonly [K in keyof T]-?: T[K];
};

interface Config {
  readonly host?: string;
  readonly port?: number;
}

type Draft = Mutable<Config>;
// { host: string; port: number }
Die Präfixe - entfernen readonly und die Optionalität.

Seit TypeScript 4.1 ermöglicht die as-Klausel das Key Remapping: Jeder Schlüssel kann im Vorbeigehen umbenannt werden, typischerweise über einen Template-Literal-Typ. Und wenn die Klausel never erzeugt, wird der Schlüssel schlicht aus dem Ergebnis entfernt: Das ist der offizielle Mechanismus, um Eigenschaften zu filtern. Beachte das & string im Beispiel: keyof T kann Schlüssel vom Typ symbol oder number enthalten, die mit einem Template-Literal nicht vereinbar sind.

TYPESCRIPT
type Getters<T> = {
  [K in keyof T & string as `get${Capitalize<K>}`]:
    () => T[K];
};

interface User { name: string; age: number }
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

type OnlyMethods<T> = {
  [K in keyof T as
    T[K] extends (...args: never[]) => unknown
      ? K : never]: T[K];
};
Umbenennen mit as, filtern durch das Erzeugen von never.

Eine oft übersehene Feinheit der Spezifikation: Auf ein Array oder ein Tupel angewendet, erzeugt ein homomorpher Mapped Type kein Objekt mit den Schlüsseln 0, 1 und length. Der Compiler bewahrt die Natur des Typs: Er transformiert die Elemente und behält die Array- oder Tupelform bei. Genau deshalb bleibt Readonly<[number, string]> ein Tupel. Diese Bewahrung verschwindet, sobald der Mapped Type nicht mehr homomorph ist, zum Beispiel bei [P in K], wobei K eine beliebige Union von Schlüsseln ist.

TYPESCRIPT
type Immutable<T> = {
  readonly [K in keyof T]: T[K];
};

type Pair = Immutable<[number, string]>;
// readonly [number, string]: the tuple survives

type List = Immutable<string[]>;
// readonly string[]
Ein homomorpher Mapped Type respektiert Arrays und Tupel.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Was passiert bei einem Key Remapping, wenn die as-Klausel für einen Schlüssel never erzeugt?
    • Die Eigenschaft bekommt den Typ never
    • Der Schlüssel wird aus dem Ergebnistyp entfernt
    • Der Compiler meldet einen Fehler
  2. Was erzeugt { readonly [K in keyof T]: T[K] }, angewendet auf das Tupel [number, string]?
    • Ein Objekt mit den Schlüsseln 0, 1 und length
    • readonly [number, string]
    • readonly (number | string)[]
    • Einen Kompilierfehler
  3. Welche Wirkung hat der Modifikator -? in einem Mapped Type?
    • Er macht die Eigenschaft optional
    • Er entfernt die Optionalität und das dadurch eingeführte undefined
    • Er entfernt den Modifikator readonly
    • Er entfernt die Eigenschaft aus dem Typ