Hintergrund
TypeScript wurde von Anfang an für die strikte Typisierung von Objekten und das Schreiben von vorhersehbarerem Code in JavaScript entwickelt. Eines der Werkzeuge zur Sicherstellung der Sicherheit beim Zugriff auf Eigenschaften von Objekten ist der keyof-Operator, der in TypeScript 2.1 eingeführt wurde. Er ermöglicht es, Typen zu erstellen, die eine Menge von string- (und symbol-) Schlüsseln darstellen, die im deklarierten Objekttyp verfügbar sind.
Problem
In reinem JavaScript können die Eigenschaften eines Objekts mit jedem beliebigen String abgefragt werden, und wenn man einen Fehler macht, erhält man undefined oder einen Fehler, der erst zur Laufzeit gefunden wird. Ohne strikte Typisierung ist es leicht, einen Tippfehler zu machen oder zu vergessen, den Schlüsselstring beim Refactoring zu aktualisieren. Außerdem ist es oft erforderlich, eine Funktion zu erstellen, die nur gültige Schlüssel eines bestimmten Objekts oder Typs akzeptiert.
Lösung
Der keyof-Operator erstellt einen union-Typ aus allen Schlüsseln des Typs. Mit seiner Hilfe können die zulässigen Schlüssel eingeschränkt, die Sicherheit der API erhöht (z. B. für Getter/Setter-Funktionen) und universelle Hilfstypen erstellt werden.
Beispielcode:
type User = { name: string; age: number; active: boolean }; type UserKey = keyof User; // "name" | "age" | "active" function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const user: User = { name: 'Tom', age: 33, active: true }; const age = getProp(user, 'age'); // Alter vom Typ number
Wichtige Merkmale:
Was gibt keyof für ein Array zurück und kann man Indizes erhalten?
keyof für ein Array gibt die Typen der Schlüssel des Objekts zurück, das das Array in JS tatsächlich ist. Normalerweise sind dies Indexstrings und spezielle Eigenschaften des Arrays.
Beispielcode:
type A = keyof number[]; // "length" | "toString" | "pop" | ... | number
Kann keyof die Schlüssel von union-types zurückgeben?
Ja, keyof von einem union-Typ gibt die Schnittmenge der Schlüssel beider Objekte und nicht deren Vereinigung zurück.
Beispielcode:
type A = {a: string, b: number } type B = {b: number, c: boolean } type C = keyof (A | B); // "b"
Was passiert, wenn eine Eigenschaft des Objekts optional ist? Unterstützt keyof "?"?
Ja, optionale Eigenschaften gehören ebenfalls zum resultierenden Typ der Schlüssel, was jedoch nicht bedeutet, dass die Eigenschaft zur Laufzeit unbedingt im Objekt vorhanden ist.
Beispielcode:
type D = { a: string; b?: number }; type DK = keyof D; // "a" | "b"
Eine Funktion getProperty(obj, key) mit einem Schlüssel vom Typ String wird geschrieben, sie wird mit einem nicht existierenden Schlüssel aufgerufen – der Fehler tritt erst zur Laufzeit auf.
Vorteile:
Nachteile:
Verwendung von Generika: getProperty<T, K extends keyof T>(), der Typ key ist streng auf die Schlüssel der Struktur beschränkt.
Vorteile:
Nachteile: