TypeScript - Utility Types

Hallo zusammen, zukünftige Codier-Zauberer! Heute machen wir uns auf eine aufregende Reise durch die magische Welt der TypeScript Utility Types. Keine Sorge, wenn Ihr neu im Programmieren seid; ich werde Euer freundlicher Guide sein, und wir werden diese Konzepte gemeinsam, Schritt für Schritt, erkunden. Also, holt Euch Eure virtuellen Zauberstäbe (Tastaturen) und tauchen wir ein!

TypeScript - Utility Types

Was sind Utility Types?

Bevor wir beginnen, lassen wir uns klarmachen, was Utility Types sind. Stellt Euch vor, Ihr habt eine Werkzeugkiste voller verschiedener Werkzeuge. Jedes Werkzeug hilft Euch, eine spezifische Aufgabe effizienter auszuführen. Genau das sind Utility Types in TypeScript - sie sind vorgefertigte Werkzeuge, die uns helfen, Typen einfach zu manipulieren und zu transformieren.

Nun, schauen wir uns jede dieser magischen Werkzeuge einzeln an!

Partial-Typ in TypeScript

Der Partial-Typ ist wie ein Zauber, der alle Eigenschaften in einem Objekt optional macht. Er ist besonders nützlich, wenn Ihr ein Objekt erstellen wollt, bei dem Ihr nicht alle Eigenschaften angeben müsst.

Sehen wir uns das in Aktion an:

interface Wizard {
  name: string;
  age: number;
  house: string;
}

function updateWizard(wizard: Wizard, fieldsToUpdate: Partial<Wizard>) {
  return { ...wizard, ...fieldsToUpdate };
}

const harryPotter: Wizard = {
  name: "Harry Potter",
  age: 11,
  house: "Gryffindor"
};

const updatedHarry = updateWizard(harryPotter, { age: 17 });
console.log(updatedHarry);
// Ausgabe: { name: "Harry Potter", age: 17, house: "Gryffindor" }

In diesem Beispiel allows Partial<Wizard> uns, nur das Alter von Harry zu aktualisieren, ohne alle anderen Eigenschaften angeben zu müssen. Es ist, als ob Ihr einen Zauberstäbe und "Partial Revelio!" sprechet!

Required-Typ in TypeScript

Der Required-Typ ist das Gegenteil von Partial. Er ist wie ein Zauber, der alle Eigenschaften in einem Objekt obligatorisch macht, selbst wenn sie ursprünglich optional waren.

interface MagicalCreature {
  name: string;
  power?: string;
  age?: number;
}

const dragon: Required<MagicalCreature> = {
  name: "Norwegian Ridgeback",
  power: "Feueratem",
  age: 2
};

// Dies würde einen Fehler verursachen:
// const unicorn: Required<MagicalCreature> = {
//   name: "Silberne Horn"
// };

Hier machen selbst wenn power und age ursprünglich optional in der Schnittstelle waren, der Required-Typ sie obligatorisch. Es ist, als ob Ihr "Accio alle Eigenschaften!" sagt!

Pick-Typ in TypeScript

Der Pick-Typ ermöglicht es Euch, einen neuen Typ zu erstellen, indem Ihr spezifische Eigenschaften von einem bestehenden Typ auswählt. Es ist wie ein Beschwörungszauber, der nur die Eigenschaften herbeiruft, die Ihr benötigt.

interface Potion {
  name: string;
  ingredients: string[];
  brewingTime: number;
  effect: string;
}

type PotionLabel = Pick<Potion, 'name' | 'effect'>;

const polyjuicePotion: PotionLabel = {
  name: "Polyjuice Potion",
  effect: "Verwandelt den Trinker in eine andere Person"
};

In diesem Beispiel haben wir einen neuen Typ PotionLabel erstellt, der nur die Eigenschaften name und effect aus der Potion-Schnittstelle enthält. Es ist perfekt für den Fall, dass Ihr nur wenige spezifische Details benötigt!

Omit-Typ in TypeScript

Der Omit-Typ ist das Gegenteil von Pick. Er erstellt einen neuen Typ, indem er spezifische Eigenschaften von einem bestehenden Typ entfernt. Denkt daran als ob Ihr einen Verschwinden-Zauber auf bestimmte Eigenschaften anwendet!

interface SpellBook {
  title: string;
  author: string;
  pages: number;
  secretSpell: string;
}

type PublicSpellBook = Omit<SpellBook, 'secretSpell'>;

const beginnerSpellBook: PublicSpellBook = {
  title: "Standard Buch der Zauber, Klasse 1",
  author: "Miranda Goshawk",
  pages: 250
};

Hier haben wir einen PublicSpellBook-Typ erstellt, der alle Eigenschaften der SpellBook-Schnittstelle enthält, mit Ausnahme von secretSpell. Es ist, als ob Ihr "Zeige mir alles außer das Geheimnis!" sagt!

Readonly-Typ in TypeScript

Der Readonly-Typ ist wie ein Schutzzauber für Eure Eigenschaften. Er macht alle Eigenschaften in einem Typ schreibgeschützt und verhindert versehentliche Änderungen.

interface Wand {
  wood: string;
  core: string;
  length: number;
}

const harryWand: Readonly<Wand> = {
  wood: "Hainbuche",
  core: "Phönixfeder",
  length: 11
};

// Dies würde einen Fehler verursachen:
// harryWand.length = 12;

Mit Readonly haben wir sichergestellt, dass一旦 ein Zauberstab erstellt wird, seine Eigenschaften nicht mehr geändert werden können. Es ist, als ob Ihr einen unzerbrechlichen Zauber auf Eure Objekte anwendet!

ReturnType-Typ in TypeScript

Der ReturnType-Utility-Typ ermöglicht es Euch, den Rückgabotyp einer Funktion zu extrahieren. Es ist wie Legiliment, um in eine Funktion zu blicken und zu sehen, was sie zurückgibt!

function castSpell(spellName: string): { name: string, power: number } {
  // Zauber logik hier
  return { name: spellName, power: Math.random() * 100 };
}

type SpellResult = ReturnType<typeof castSpell>;

const lumos: SpellResult = {
  name: "Lumos",
  power: 50
};

In diesem Beispiel wird SpellResult als { name: string, power: number } inferiert, was der Rückgabetyp von castSpell ist. Es ist unglaublich nützlich bei der Arbeit mit komplexen Funktionen!

Record-Typ in TypeScript

Der Record-Typ ist ein mächtiger Zauber, der einen Objekttyp mit einem bestimmten Schlüsseltyp und Werttyp erstellt. Es ist wie ein Beschwörungszauber, bei dem Ihr definiert, welche Schlüssel und Werte verwendet werden sollen.

type HouseCup = Record<string, number>;

const housePoints: HouseCup = {
  "Gryffindor": 472,
  "Hufflepuff": 352,
  "Ravenclaw": 426,
  "Slytherin": 472
};

Hier ist HouseCup ein Typ, bei dem die Schlüssel strings (Hausnamen) und die Werte numbers (Punkte) sind. Es stellt sicher, dass unser Hauspunkte-Objekt die richtige Struktur hat.

NonNullable-Typ in TypeScript

Der NonNullable-Typ ist wie ein Zauber, der null und undefined-Werte banniert. Er erstellt einen neuen Typ, indem er null und undefined von einem gegebenen Typ ausschließt.

type MagicalItem = string | number | null | undefined;

type DefiniteMagicalItem = NonNullable<MagicalItem>;

const definiteItem: DefiniteMagicalItem = "Unsichtbarkeitstuch";
// Dies würde einen Fehler verursachen:
// const nullItem: DefiniteMagicalItem = null;

In diesem Beispiel ist DefiniteMagicalItem ein Typ, der entweder string oder number sein kann, aber nicht null oder undefined. Es ist perfekt, wenn Ihr sicherstellen wollt, dass Ihr mit tatsächlichen Werten arbeitet!

Utility Types Cheat Sheet

Hier ist eine schnelle Referenztabelle für alle Utility Types, die wir behandelt haben:

Utility Type Beschreibung Beispiel
Partial Macht alle Eigenschaften in T optional Partial<Wizard>
Required Macht alle Eigenschaften in T obligatorisch Required<MagicalCreature>
Pick<T, K> Erstellt einen Typ mit nur den Eigenschaften K aus T Pick<Potion, 'name' | 'effect'>
Omit<T, K> Erstellt einen Typ ohne die Eigenschaften K aus T Omit<SpellBook, 'secretSpell'>
Readonly Macht alle Eigenschaften in T schreibgeschützt Readonly<Wand>
ReturnType Extrahiert den Rückgabetyp einer Funktionstyp T ReturnType<typeof castSpell>
Record<K, T> Erstellt einen Objekttyp mit Schlüsseln vom Typ K und Werten vom Typ T Record<string, number>
NonNullable Erstellt einen Typ, indem null und undefined von T ausgeschlossen werden NonNullable<MagicalItem>

Und das war's, junge Zauberer! Ihr habt nun die grundlegenden Zauber der TypeScript Utility Types gemeistert. Wie jede Magie werden diese Typen mit der Praxis mächtiger. Also, experimentiert weiter, und bald werdet Ihr diese Typen so mühelos anwenden können, wie wenn Ihr "Wingardium Leviosa" sagt!

Credits: Image by storyset