Partial
Helden verändern sich ständig: Sie steigen auf, verlieren im Kampf Leben, finden Gold. Meistens ändern sich nur ein oder zwei Eigenschaften, der Rest bleibt gleich. In dieser Lektion lernst du Utility-Typen kennen: generische Typen, die in TypeScript eingebaut sind und aus einem Typ, den du schon hast, einen neuen machen. Einen davon kennst du bereits, Record<K, V>. Der erste neue ist genau für solche Änderungen gemacht. Vorher kommt aber ein neues Stück JavaScript, das du dafür brauchst.
Spread. Drei Punkte vor einem Objekt innerhalb von geschweiften Klammern, { ...kira }, kopieren alle seine Eigenschaften in ein neues Objekt. Das nennt man Spread. Eigenschaften, die danach geschrieben werden, kommen zum neuen Objekt hinzu oder ersetzen die kopierten mit demselben Namen:
const kira = { name: "Kira", stufe: 3, gold: 120 };
const staerker = { ...kira, stufe: 4 };
console.log(staerker);
console.log(kira);Das gibt aus:
{ name: "Kira", stufe: 4, gold: 120 }
{ name: "Kira", stufe: 3, gold: 120 }Das Original bleibt, wie es war: Spread erzeugt ein neues Objekt. Du kannst auch mehrere Objekte kopieren, { ...a, ...b }. Haben beide eine Eigenschaft mit demselben Namen, gewinnt die, die später kommt, hier die aus b. Die drei Punkte funktionieren auch bei Arrays: [...beute, "Alte Karte"] ist ein neues Array mit allem aus beute und einem Eintrag mehr am Ende.
Partial. Jetzt eine Funktion, die einen Helden aktualisiert: Sie bekommt den Helden und die Änderungen und gibt einen neuen, aktualisierten Helden zurück. Aber welchen Typ sollen die Änderungen haben? Mit Held verlangt TypeScript alle Eigenschaften, obwohl du nur zwei ändern willst:
interface Held {
name: string;
stufe: number;
leben: number;
gold: number;
}
function aktualisiereHeld(held: Held, aenderungen: Held): Held {
return { ...held, ...aenderungen };
}
const kira: Held = { name: "Kira", stufe: 3, leben: 50, gold: 120 };
const nachAuftrag = aktualisiereHeld(kira, { stufe: 4, gold: 160 });main.ts(13,44): error TS2739: Type '{ stufe: number; gold: number; }' is missing the following properties from type 'Held': name, lebenDu könntest einen zweiten Typ schreiben, in dem jede Eigenschaft optional ist, aber dann müsstest du beide Typen ändern, sobald sich Held ändert. Partial<Held> erledigt das für dich: Es ist Held mit lauter optionalen Eigenschaften, als hättest du name?: string, stufe?: number und so weiter geschrieben. Mit aenderungen: Partial<Held> akzeptiert die Funktion { stufe: 4, gold: 160 }, eine einzelne Eigenschaft oder sogar {}. Und wenn du Held eine Eigenschaft hinzufügst, hat sie Partial<Held> auch.
Optional heißt nicht, dass alles erlaubt ist. TypeScript prüft weiterhin die Namen und die Typen der Eigenschaften:
aktualisiereHeld(kira, { lebn: 60 });
aktualisiereHeld(kira, { leben: "60" });main.ts(13,26): error TS2561: Object literal may only specify known properties, but 'lebn' does not exist in type 'Partial<Held>'. Did you mean to write 'leben'?
main.ts(14,26): error TS2322: Type 'string' is not assignable to type 'number'.Innerhalb der Funktion kann jede Eigenschaft von aenderungen fehlen, deshalb gehört undefined zu ihrem Typ, genau wie bei den optionalen Eigenschaften in der Lektion „Objekttypen“. { ...held, ...aenderungen } kümmert sich darum: Was in aenderungen fehlt, ersetzt nichts, also behält der Held seinen alten Wert.
Typische Fehler:
- Die falsche Reihenfolge,
{ ...aenderungen, ...held }. Die alten Werte des Helden kommen zuletzt, ersetzen also die Änderungen, und es ändert sich nichts. Die Änderungen stehen immer am Ende. - Eine Eigenschaft vor einem Spread, der sie auch enthält. In
{ stufe: 4, ...kira }würde Kiras eigenestufedie 4 ersetzen, deshalb meldet TypeScript:main.ts(2,20): error TS2783: 'stufe' is specified more than once, so this usage will be overwritten.
So schreibst du es:
Anweisungen
- 1
Schreibe unter
kiraeine FunktionaktualisiereHeld(held: Held, aenderungen: Partial<Held>): Held, die einen neuen Helden zurückgibt,{ ...held, ...aenderungen }. - 2
Kira hat einen Auftrag abgeschlossen: Sie ist auf Stufe 4 aufgestiegen und hat 160 Gold. Speichere unter der Funktion
aktualisiereHeld(kira, { stufe: 4, gold: 160 })in einer KonstantennachAuftragund gib sie aus:{ name: "Kira", stufe: 4, leben: 50, gold: 160 } - 3
Gib darunter auch
kiraaus. Der ursprüngliche Held hat sich nicht verändert:{ name: "Kira", stufe: 4, leben: 50, gold: 160 } { name: "Kira", stufe: 3, leben: 50, gold: 120 }