Menu

TypeScript Indexed Access Types: T[K], T[number] und mehr

Ein Indexed Access Type liest den Typ einer Eigenschaft aus einem anderen Typ: Person["age"] ist number. T["key"], Union-Schlüssel, T[keyof T], T[number] für Array-Elemente, Tupel-Indizes und (typeof arr)[number], um ein const-Array in eine Union zu verwandeln.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Ein Indexed Access Type schlägt den Typ einer Eigenschaft in einem anderen Typ nach, mit derselben Klammersyntax, die JavaScript für den Eigenschaftszugriff verwendet. Person["age"] ist number, und Person["address"]["city"] ist string.

Der Vorteil ist eine einzige Quelle der Wahrheit. Age ist keine zweite Kopie von number: Ändert sich Person["age"] zu string, ändert sich jeder Typ mit, der als Person["age"] geschrieben ist. Indexed Access Types existieren nur beim Kompilieren; sie erzeugen kein JavaScript.

Union-Schlüssel und T[keyof T]

Der Index kann eine Union von Schlüsseln sein. Das Ergebnis ist die Union der Eigenschaftstypen:

Product[keyof Product] heißt auf Typebene "irgendein Eigenschaftswert von Product". Einen Schlüssel abzufragen, den es nicht gibt, ist ein Compilerfehler: Product["price"] ergibt error TS2339: Property 'price' does not exist on type 'Product'.

Optionale Eigenschaften enthalten undefined

Mit strictNullChecks (unter strict aktiv) enthält der Typ einer optionalen Eigenschaft undefined, und ihr Indexed Access Type ebenso:

type Profile = { name: string; nickname?: string };

type Nick = Profile["nickname"]; // string | undefined

Um das undefined loszuwerden, umschließe den Typ: NonNullable<Profile["nickname"]> ist string.

Elementtypen von Arrays mit T[number]

Arrays werden mit Zahlen indiziert, also ergibt ein Array-Typ, der mit number indiziert wird, den Elementtyp. Das funktioniert auch über mehrere Ebenen:

Das ist nützlich, wenn ein Typ aus einer Quelle kommt, die du nicht kontrollierst, etwa einem generierten API-Client: ApiResponse["data"]["users"][number] benennt den User-Typ, ohne dass ihn jemand exportiert haben muss.

Tupel: Indizieren nach Position

Einen Tupel-Typ kannst du mit einer bestimmten Position indizieren, mit number für die Union aller Elementtypen und mit "length" für seine Länge als Literaltyp:

(typeof arr)[number]: eine Union aus einem const-Array

Der häufigste Einsatz in der Praxis: Du hältst eine Liste erlaubter Werte als Array (damit du zur Laufzeit darüber iterieren kannst) und leitest daraus den Union-Typ ab (damit der Compiler ihn prüft).

Zwei Teile sorgen dafür, dass es funktioniert. as const macht das Array zu einem readonly-Tupel aus Literaltypen; ohne das ist ROLES ein string[] und (typeof ROLES)[number] nur string. Dann macht typeof aus dem Wert einen Typ, und [number] sammelt seine Elemente in einer Union. Die Klammern sind optional (typeof ROLES[number] bedeutet dasselbe), machen aber die Reihenfolge der Operationen deutlich.

Einen String gegen das Array prüfen

Dieses readonly-Tupel hat eine Überraschung parat. Seine Methode includes akzeptiert nur den Elementtyp, also kannst du ihr keinen beliebigen String übergeben:

index.ts(6,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"admin" | "editor" | "viewer"'.

Erweitere das Array für die Prüfung auf readonly string[] und mach aus der Funktion einen Type Guard, damit eine erfolgreiche Prüfung den Wert eingrenzt:

Mit diesem Muster hast du eine Liste für beide Aufgaben: Die Laufzeitprüfung nutzt das Array, und der Typ wird daraus abgeleitet, also können beide nicht auseinanderlaufen.

Indexed Access in Generics: T[K]

Innerhalb eines Generics ist T[K] mit K extends keyof T der Typ der Eigenschaft, die der Aufrufer gewählt hat:

function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {
  return items.map((item) => item[key]);
}

const users = [
  { name: "Ada", age: 36 },
  { name: "Linus", age: 28 },
];

const names = pluck(users, "name"); // string[]
const ages = pluck(users, "age");   // number[]

Erst der Constraint K extends keyof T macht T[K] zulässig. Ohne ihn kann TypeScript nicht wissen, dass K ein Schlüssel von T ist, und meldet error TS2536: Type 'K' cannot be used to index type 'T'.

Syntax im Überblick

GeschriebenBedeutungBeispielergebnis
T["key"]Typ einer EigenschaftPerson["age"] ist number
T["a" | "b"]Union dieser Eigenschaftstypenstring | number
T[keyof T]Union aller Eigenschaftstypenjeder Werttyp
T["a"]["b"]verschachtelte EigenschaftPerson["address"]["city"]
Arr[number]Elementtyp eines ArraysUser[] ergibt User
Tup[0]Tupel-Element an einer PositionTyp des ersten Elements
Tup["length"]Tupel-Länge als Literal3
(typeof arr)[number]Union der Werte eines const-Arrays"admin" | "editor"
T[typeof key]Index mit dem Typ einer Konstantewie T["name"]

Der Index ist immer ein Typ. Person[key], wobei key eine const-Variable ist, scheitert mit zwei Fehlern: error TS2538: Type 'key' cannot be used as an index type. und error TS2749: 'key' refers to a value, but is being used as a type here. Did you mean 'typeof key'?.

Häufig gestellte Fragen

Was ist ein Indexed Access Type in TypeScript?

Ein Typ der Form T[K], der den Typ der Eigenschaft K im Typ T nachschlägt. Mit type Person = { name: string; age: number } ist Person["age"] gleich number. Er nutzt dieselbe Klammersyntax wie der Eigenschaftszugriff in JavaScript, arbeitet aber beim Kompilieren mit Typen.

Wie bekomme ich den Typ eines Array-Elements in TypeScript?

Indiziere den Array-Typ mit number: Für type Users = User[] ist Users[number] gleich User. Für einen Array-Wert kombinierst du das mit typeof: (typeof users)[number].

Wie mache ich aus einem Array von Strings einen Union-Typ?

Deklariere das Array mit as const, damit TypeScript die Literalwerte behält, und indiziere es dann mit number: const roles = ["admin", "editor"] as const; type Role = (typeof roles)[number]; ergibt "admin" | "editor". Ohne as const ist der Elementtyp nur string.

Warum kann ich keine Variable als Index in einem Indexed Access Type verwenden?

Der Index muss ein Typ sein. Person[key] mit const key = "name" scheitert (Fehler TS2538 und TS2749), weil key ein Wert ist. Schreibe Person[typeof key] oder verwende das Literal direkt: Person["name"].

Was bedeutet T[keyof T]?

Es indiziert T mit der Union aller seiner Schlüssel, das Ergebnis ist also die Union aller seiner Eigenschaftstypen. Für { a: string; b: number } ist es string | number. Auf Typebene heißt das "irgendein Wert dieses Objekts".

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S