TypeScript bietet eine leistungsstarke Typsystem-Erweiterung für JavaScript, die es Entwicklern ermöglicht, sicheren und wartbaren Code zu schreiben. Nachdem im Artikel Grundlagen von TypeScript: Typen und Interfaces die Grundlagen erklärt wurden, möchten wir in diesem Beitrag tiefer in die fortgeschrittenen Typen eintauchen. Diese erweiterten Konzepte sind besonders nützlich, wenn es darum geht, komplexe und dynamische Anwendungen zu entwickeln.

Union Types

Union Types („Vereinigungs-Typen“) erlauben es, einen Wert zu definieren, der einer von mehreren Typen sein kann:

let value: string | number;
value = "Hello"; // erlaubt
value = 42; // erlaubt
value = true; // Fehler

Mit Union Types lassen sich Szenarien modellieren, in denen Variablen mehrere Typen annehmen können.

Intersection Types

Intersection Types („Schnittmengen-Typen“) kombinieren mehrere Typen zu einem neuen Typ, der alle Eigenschaften der kombinierten Typen enthält:

type A = { name: string };
type B = { age: number };
type C = A & B;

const person: C = {
  name: "Max",
  age: 30,
};

Mit Union Types lassen sich Szenarien modellieren, in denen Variablen mehrere Typen annehmen können.

CloudDNA Bücher

Mapped Types

Mapped Types sind eine leistungsfähige Möglichkeit, um Typen dynamisch zu generieren. Sie verwenden Syntax wie

<span>keyof</span>

und Index-Signaturen:

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Person = {
  name: string;
  age: number;
};

const person: Readonly<Person> = {
  name: "Anna",
  age: 25,
};

// person.name = "Maria"; // Fehler: Eigenschaft ist schreibgeschützt

Mapped Types sind besonders hilfreich, um Utility-Typen zu erstellen, die konsistent und wartbar sind.

Conditional Types

Conditional Types erlauben es, basierend auf einer Bedingung einen Typ auszuwählen:

type IsString<T> = T extends string ? true : false;

let result: IsString<string>; // true
let result2: IsString<number>; // false

Conditional Types sind äußerst nützlich, um generische Typen flexibler und dynamischer zu gestalten.

Template Literal Types

Template Literal Types erlauben es, Typen auf Basis von Template-Strings zu erstellen:

type Color = "red" | "blue";
type Shade = "dark" | "light";
type ColorVariant = `${Shade}-${Color}`;

let variant: ColorVariant;
variant = "dark-red"; // erlaubt
variant = "light-green"; // Fehler

Diese Typen sind ideal, um strikte Vorgaben für benutzerdefinierte Strings zu definieren.

Utility-Typen

TypeScript liefert eine Reihe von vordefinierten Utility-Typen, die häufige Anforderungen abdecken:

  • <span>Partial&lt;T&gt;</span>

    : Macht alle Eigenschaften eines Typs optional.

  • <span>Required&lt;T&gt;</span>

    : Macht alle Eigenschaften eines Typs obligatorisch.

  • <span>Pick&lt;T, K&gt;</span>

    : Wählt eine Teilmenge von Eigenschaften eines Typs aus.

  • <span>Omit&lt;T, K&gt;</span>

    : Entfernt spezifische Eigenschaften aus einem Typ.

Beispiel:

type Todo = {
  title: string;
  description: string;
  completed: boolean;
};

const todo: Partial<Todo> = {
  title: "Learn TypeScript",
};

const fullTodo: Required<Todo> = {
  title: "Learn TypeScript",
  description: "Understand advanced types",
  completed: false,
};

Rekursive Typen

Mit rekursiven Typen lassen sich komplexe Datenstrukturen wie verschachtelte Objekte oder Baumstrukturen abbilden:

type Json = string | number | boolean | null | Json[] | { [key: string]: Json };

const jsonObject: Json = {
  name: "Alice",
  children: [
    {
      name: "Bob",
    },
  ],
};

Fazit

Fortgeschrittene Typen in TypeScript bieten eine enorme Flexibilität und Kontrolle über den Code. Sie erleichtern die Implementierung von robusten und skalierbaren Anwendungen und helfen dabei, potenzielle Fehler frühzeitig zu erkennen. Wenn Sie diese Konzepte meistern, werden Sie in der Lage sein, selbst komplexeste Typisierungsprobleme elegant zu lösen. Nutzen Sie diese Werkzeuge, um Ihren Code sicherer und zukunftssicher zu gestalten!