Warum Generics
Manche Funktionen kümmert es nicht, was ein Array enthält. Eine Funktion, die das erste Element zurückgibt, funktioniert für Namen, Preise und Helden auf dieselbe Weise. In JavaScript würdest du sie einmal schreiben:
function erstes(elemente) {
return elemente[0];
}In TypeScript braucht der Parameter einen Typ, sonst bekommst du Parameter 'elemente' implicitly has an 'any' type. (TS7006). Aber welchen? Das Array kann alles enthalten. Probieren wir die Möglichkeiten aus, die du kennst.
Möglichkeit 1: any. Ein Parameter vom Typ any[] akzeptiert jedes Array, und die Funktion gibt any zurück:
type Held = { name: string; leben: number };
// Gibt das erste Element eines Arrays zurück
function erstes(elemente: any[]): any {
return elemente[0];
}
const helden: Held[] = [
{ name: "Kira", leben: 50 },
{ name: "Bruno", leben: 70 },
];
const traenke: string[] = ["Heiltrank", "Manatrank"];
const anfuehrer = erstes(helden);
console.log(`Anführer: ${anfuehrer.name}, Leben ${anfuehrer.lebn}`);
const trank = erstes(traenke);
console.log(trank.toUppercase());Das gibt aus:
Anführer: Kira, Leben undefined
TypeError: trank.toUppercase is not a functionTypeScript hat keinen der beiden Tippfehler gemeldet. Es weiß nicht, dass anfuehrer ein Held und trank ein Text ist: Beide sind any, und bei any wird nichts geprüft. Die Fehler von JavaScript sind zurück: undefined statt einer Zahl und ein Absturz, während das Programm läuft.
Möglichkeit 2: unknown. In der Lektion über Unions und Narrowing hast du die sichere Version von any kennengelernt. Bei unknown lässt TypeScript dich das Ergebnis erst verwenden, wenn du es eingegrenzt hast:
function erstes(elemente: unknown[]): unknown {
return elemente[0];
}
const namen = ["Kira", "Bruno", "Lena"];
const anfuehrer = erstes(namen);
console.log(anfuehrer.toUpperCase());TypeScript meldet:
main.ts(7,13): error TS18046: 'anfuehrer' is of type 'unknown'.Das ist sicher, aber nicht besonders nützlich. Du weißt, dass das erste Element von namen ein Text ist; TypeScript hat es auf dem Weg durch die Funktion vergessen. Du müsstest nach jedem Aufruf typeof anfuehrer === "string" prüfen.
Möglichkeit 3: eine Funktion für jeden Typ.
function ersterName(namen: string[]): string {
return namen[0];
}
function ersterHeld(helden: Held[]): Held {
return helden[0];
}Jetzt prüft TypeScript alles: ersterHeld(helden).lebn ist ein Fehler. Aber beide Funktionen haben denselben Rumpf, und jeder neue Typ braucht eine weitere Kopie: ersterTrank, ersterAuftrag, ersterMonster …
Wir wollen eine Funktion, die sagt: „Egal, welchen Typ die Elemente haben, ich gebe ein Element desselben Typs zurück.“ TypeScript kann genau das: Generics, das Thema dieser Lektion. Deine erste generische Funktion schreibst du in der nächsten Übung. Probiere zuerst Möglichkeit 3 im Editor aus und sieh, wohin sie führt.
So schreibst du es:
Anweisungen
- 1
Führe das Programm aus: Es gibt
Leben undefinedundheilt undefinedaus, und TypeScript beschwert sich nicht. Schreibe eine FunktionersterHeld(helden: Held[]): Heldmit demselben Rumpf wieerstesund verwende sie füranfuehrerstatterstes. TypeScript findet dann den Tippfehler in der Zeile mitanfuehrer.lebn. Behebe ihn. - 2
Mache dasselbe für die Tränke: Schreibe
ersterTrank(traenke: Trank[]): Trank, verwende die Funktion fürtrankund behebe den Fehler, den TypeScript findet. Das Programm gibt dann aus:Anführer: Kira, Leben 50 Trank: Heiltrank, heilt 20Jetzt prüft TypeScript beide Zeilen. Aber du hast zwei Funktionen mit demselben Rumpf, und der nächste Typ bräuchte eine dritte. In der nächsten Übung ersetzt eine einzige Funktion alle.