ProgrammierungFullstack-Entwickler

Wie funktioniert der keyof-Operator in TypeScript, wofür wird er verwendet und wie beeinflusst er das Design sicherer Funktionen und APIs?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

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:

  • Ermöglicht die Deklaration von "Schlüssel"-Typen, die von der Struktur des Objekts abhängen.
  • Macht Getter/Setter-Funktionen für Eigenschaften maximal typensicher – Tippfehler und nicht existente Schlüssel sind ausgeschlossen.
  • Funktioniert auch mit symbolischen Eigenschaften (symbol) ab TypeScript 2.7 und höher.

Tückische Fragen.

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"

Typische Fehler und Anti-Pattern

  • Verwenden von konstanten Strings für Schlüssel anstelle von keyof – Verlust der Typisierung.
  • Annehmen, dass keyof für union eine Vereinigung und keine Schnittmenge zurückgibt.
  • Erwarten, dass keyof nur ausdrücklich deklarierte Schlüssel, jedoch keine geerbten, berücksichtigt.

Beispiel aus der Praxis

Negativer Fall

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:

  • Universeller Code.

Nachteile:

  • Keine Überprüfung zur Compile-Zeit, mögliche Fehler beim Refactoring, anfällig für Tippfehler.

Positiver Fall

Verwendung von Generika: getProperty<T, K extends keyof T>(), der Typ key ist streng auf die Schlüssel der Struktur beschränkt.

Vorteile:

  • Absolute Typensicherheit, Tippfehler oder Fehler im Schlüssel sind unmöglich.

Nachteile:

  • Der Code ist etwas komplexer, Generika sind Neulingen nicht immer klar.