keyof
Manchmal steht der Schlüssel, den du lesen willst, in einer Variablen. In JavaScript würdest du werte[schluessel] mit eckigen Klammern schreiben. In TypeScript:
type Werte = { staerke: number; geschick: number; magie: number };
const kira: Werte = { staerke: 6, geschick: 9, magie: 4 };
function holeWert(werte: Werte, schluessel: string): number {
return werte[schluessel];
}
console.log(holeWert(kira, "geschick"));TypeScript meldet:
main.ts(4,12): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Werte'.
No index signature with a parameter of type 'string' was found on type 'Werte'.TypeScript lehnt es ab, weil schluessel jeder Text sein kann, zum Beispiel "magi", und Werte nur drei Schlüssel hat. Für jeden anderen Schlüssel wäre werte[schluessel] gleich undefined und keine Zahl, also kann TypeScript nicht sagen, welchen Typ es hat („implicitly has an 'any' type“).
Der Typ für „einen der Schlüssel von Werte“ ist keyof Werte:
type Werte = { staerke: number; geschick: number; magie: number };
type WertName = keyof Werte; // "staerke" | "geschick" | "magie"keyof nimmt einen Objekttyp und gibt dir die Union seiner Schlüssel, als Literaltypen. Weil sie aus dem Typ berechnet wird, kann sie nicht veralten: Füge Werte einen Schlüssel hinzu, und keyof Werte hat ihn auch. Mit schluessel: keyof Werte ist werte[schluessel] erlaubt, und ein falsch geschriebener Schlüssel wird dort gefunden, wo du die Funktion aufrufst:
type Werte = { staerke: number; geschick: number; magie: number };
const kira: Werte = { staerke: 6, geschick: 9, magie: 4 };
function holeWert(werte: Werte, schluessel: keyof Werte): number {
return werte[schluessel];
}
console.log(holeWert(kira, "geschick"));
console.log(holeWert(kira, "magi"));TypeScript meldet:
main.ts(7,28): error TS2345: Argument of type '"magi"' is not assignable to parameter of type 'keyof Werte'.keyof mit Generics. Wenn die Eigenschaften verschiedene Typen haben, reicht keyof allein nicht. Ein Monster hat einen name (einen Text) und leben (eine Zahl). Eine Funktion mit schluessel: keyof Monster gibt string | number zurück: TypeScript weiß nicht, welchen Schlüssel du übergibst, also könnte das Ergebnis beides sein. Eine generische Funktion behält den genauen Typ:
type Monster = { name: string; leben: number };
function holeEigenschaft<K extends keyof Monster>(monster: Monster, schluessel: K): Monster[K] {
return monster[schluessel];
}
const troll: Monster = { name: "Troll", leben: 80 };
console.log(holeEigenschaft(troll, "name").toUpperCase());
console.log(holeEigenschaft(troll, "leben") - 30);Das gibt aus:
TROLL
50K extends keyof Monster ist eine Einschränkung: K muss einer der Schlüssel sein. Und Monster[K] ist „der Typ der Eigenschaft K von Monster“. In holeEigenschaft(troll, "name") ist K gleich "name", also ist das Ergebnis ein Monster["name"], und das ist ein string; für "leben" ist es ein number. (In der Lektion Utility Types erfährst du mehr über solche Typen.)
So schreibst du es:
Anweisungen
- 1
Ändere den Typ des Parameters
schluessel(mitkeyof), sodass er nur die Schlüssel vonHeldakzeptiert. TypeScript findet dann den falsch geschriebenen Schlüssel in einem der Aufrufe. Behebe ihn, sodass das Programm Folgendes ausgibt:name: Kira stufe: 3 - 2
Schreibe eine generische Funktion
holeEigenschaft<K extends keyof Held>(held: Held, schluessel: K): Held[K], die die Eigenschaftschluesseldes Helden zurückgibt. - 3
Füge diese beiden Zeilen am Ende hinzu. Sie funktionieren nur, wenn
holeEigenschaftden genauen Typ zurückgibt: einen Text für"heldenKlasse", eine Zahl für"gold".console.log(holeEigenschaft(kira, "heldenKlasse").toUpperCase()); console.log(holeEigenschaft(kira, "gold") + 50);Das Programm gibt aus:
name: Kira stufe: 3 WALDLÄUFERIN 170