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
| Geschrieben | Bedeutung | Beispielergebnis |
|---|---|---|
T["key"] | Typ einer Eigenschaft | Person["age"] ist number |
T["a" | "b"] | Union dieser Eigenschaftstypen | string | number |
T[keyof T] | Union aller Eigenschaftstypen | jeder Werttyp |
T["a"]["b"] | verschachtelte Eigenschaft | Person["address"]["city"] |
Arr[number] | Elementtyp eines Arrays | User[] ergibt User |
Tup[0] | Tupel-Element an einer Position | Typ des ersten Elements |
Tup["length"] | Tupel-Länge als Literal | 3 |
(typeof arr)[number] | Union der Werte eines const-Arrays | "admin" | "editor" |
T[typeof key] | Index mit dem Typ einer Konstante | wie 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".