Appearance
Kapitel 7: Generics (Generische Typen)
🎯 Lernziele
In diesem Kapitel lernen Sie:
- ✅ Was Generics sind und warum sie wichtig sind
- ✅ Generische Funktionen
- ✅ Generische Interfaces
- ✅ Generische Klassen
- ✅ Generische Constraints (Einschränkungen)
- ✅ Standard-Generik-Typen
- ✅ Praxis: Generische Tool-Funktionen
7.1 Was sind Generics?
📖 Einfache Definition
Generics erlauben Ihnen, Typparameter zu definieren, die zur Laufzeit mit einem konkreten Typ ersetzt werden.
💡 Kernkonzept
Generics = Platzhalter für Typen
Wie Funktionsparameter Werte repräsentieren, repräsentieren Generics Typen.
🎨 Visuelle Erklärung
Ohne Generics:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ function │ │ function │ │ function │
│ identity(x:T) │ │ identity(x:string) │ identity(x:number) │
│ : T │ │ : string │ │ : number │
└─────────────────┘ └─────────────────┘ └─────────────────┘
↓ ↓ ↓
Duplizierter Code Duplizierter Code Schwer zu warten
Mit Generics:
┌─────────────────┐
│ function │
│ identity<T>(x:T) │ ← T ist ein Typparameter
│ : T │
└─────────────────┘
↓
Ein einziger, wiederverwendbarer Code!7.2 Warum Generics verwenden?
❌ Problem ohne Generics
typescript
// ❌ Lösung 1: any verwenden (verliert Typsicherheit)
function identity1(arg: any): any {
return arg;
}
let result1 = identity1("Hallo");
// result1 ist vom Typ any (keine Autovervollständigung!)
// ❌ Lösung 2: Überladung (viel Code)
function identity2(x: string): string;
function identity2(x: number): number;
function identity2(x: any): any {
return x;
}✅ Lösung mit Generics
typescript
// ✅ Generische Funktion
function identity<T>(arg: T): T {
return arg;
}
// Typ wird automatisch abgeleitet
let result1 = identity("Hallo"); // Typ: string
let result2 = identity(123); // Typ: number
// Oder Typ explizit angeben
let result3 = identity<string>("Welt");7.3 Generische Funktionen
📖 Grundlegende Syntax
typescript
function funktionsname<T>(parameter: T): T {
// ...
}💻 Code-Beispiel
typescript
// Einfache generische Funktion
function identity<T>(arg: T): T {
return arg;
}
// Verwendung
const str = identity<string>("Hallo");
const num = identity<number>(123);
const bool = identity<boolean>(true);
console.log(str); // Ausgabe: Hallo
console.log(num); // Ausgabe: 123
console.log(bool); // Ausgabe: true🎨 Type Inference (Typableitung)
TypeScript kann den Typ oft automatisch erkennen:
typescript
// Typ wird automatisch abgeleitet (keine Angabe erforderlich)
const str = identity("Hallo"); // T wird zu string abgeleitet
const num = identity(123); // T wird zu number abgeleitet7.4 Mehrere Typparameter
💻 Code-Beispiel
typescript
// Mehrere Typparameter
function pair<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
// Verwendung
const p1 = pair(1, "Eins"); // [number, string]
const p2 = pair("name", "Max"); // [string, string]
const p3 = pair(true, 123); // [boolean, number]
console.log(p1); // Ausgabe: [1, "Eins"]
console.log(p2); // Ausgabe: ["name", "Max"]
console.log(p3); // Ausgabe: [true, 123]7.5 Generische Interfaces
📖 Einfache Definition
Interfaces können generische Typparameter haben.
💻 Code-Beispiel
typescript
// Generisches Interface
interface Response<T> {
success: boolean;
data: T;
message?: string;
}
// Verwendung mit verschiedenen Typen
interface User {
id: number;
name: string;
}
interface Product {
id: number;
title: string;
price: number;
}
// Response mit User-Daten
const userResponse: Response<User> = {
success: true,
data: { id: 1, name: "Max" }
};
// Response mit Product-Daten
const productResponse: Response<Product> = {
success: true,
data: { id: 101, title: "Laptop", price: 999.99 }
};
console.log(userResponse.data.name); // Ausgabe: Max
console.log(productResponse.data.price); // Ausgabe: 999.997.6 Generische Klassen
📖 Einfache Definition
Klassen können generische Typparameter haben.
💻 Code-Beispiel
typescript
// Generische Klasse
class Storage<T> {
private data: T;
constructor(data: T) {
this.data = data;
}
getData(): T {
return this.data;
}
setData(data: T): void {
this.data = data;
}
}
// Verwendung
const stringStorage = new Storage<string>("Hallo");
console.log(stringStorage.getData()); // Ausgabe: Hallo
stringStorage.setData("Welt");
console.log(stringStorage.getData()); // Ausgabe: Welt
// number
const numberStorage = new Storage<number>(123);
console.log(numberStorage.getData()); // Ausgabe: 1237.7 Generische Constraints (Einschränkungen)
📖 Einfache Definition
Constraints schränken ein, welche Typen für einen Typparameter erlaubt sind.
💻 Code-Beispiel
typescript
// Constraint: T muss ein Objekt mit der Eigenschaft length haben
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): void {
console.log(arg.length);
}
// ✅ Erlaubt
logLength("Hallo"); // string hat length
logLength([1, 2, 3]); // Array hat length
// ❌ Fehler
logLength(123); // number hat keine length🎨 Weiteres Beispiel
typescript
// Constraint: T muss ein Objekt sein
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = {
name: "Max",
age: 25
};
// ✅ Erlaubt
const name = getProperty(user, "name"); // Typ: string
const age = getProperty(user, "age"); // Typ: number
// ❌ Fehler: "email" existiert nicht in user
const email = getProperty(user, "email");7.8 Standard-Generik-Typen (Default Type Parameters)
📖 Einfache Definition
Sie können Standardtypen für Generics angeben.
💻 Code-Beispiel
typescript
// Standardtyp: string
interface Container<T = string> {
value: T;
}
// ✅ Mit Typangabe
const numContainer: Container<number> = { value: 123 };
// ✅ Ohne Typangabe (verwendet Standard: string)
const strContainer: Container = { value: "Hallo" };7.9 Praxis: Generische Tool-Funktionen
💻 Vollständiges Beispiel
typescript
// 1. Rückgabewert-Typ abrufen
function getReturnType<T>(fn: (...args: any[]) => T): T {
// ...
return {} as T;
}
// 2. Array umdrehen
function reverseArray<T>(array: T[]): T[] {
return array.reverse();
}
// 3. Erstes Element abrufen
function getFirstElement<T>(array: T[]): T | undefined {
return array[0];
}
// 4. Eindeutigen Wert erstellen
function unique<T>(array: T[]): T[] {
return [...new Set(array)];
}
// Verwendung
console.log(reverseArray([1, 2, 3])); // Ausgabe: [3, 2, 1]
console.log(getFirstElement(["a", "b", "c"])); // Ausgabe: a
console.log(unique([1, 2, 2, 3, 3])); // Ausgabe: [1, 2, 3]📝 Zusammenfassung
In diesem Kapitel haben Sie gelernt:
- ✅ Generics ermöglichen typsichere, wiederverwendbare Funktionen und Klassen
- ✅ Generische Funktionen:
function identity<T>(arg: T): T - ✅ Generische Interfaces:
interface Response<T> - ✅ Generische Klassen:
class Storage<T> - ✅ Constraints:
T extends ...schränkt erlaubte Typen ein - ✅ Standardtypen:
interface Container<T = string>
🎯 Nächstes Kapitel
Im Kapitel 8 lernen wir tsconfig.json (TypeScript-Konfiguration für Projekte)!
👉 Weiter zu Kapitel 8: tsconfig.json
❓ Häufig gestellte Fragen
F: Wann sollte ich Generics verwenden?
A: Wenn Sie Funktionen oder Klassen schreiben, die mit verschiedenen Typen arbeiten sollen, aber dabei typsicher bleiben wollen.
F: Was ist der Unterschied zwischen any und Generics?
A:
any: Deaktiviert Typprüfung (unsicher)any: Verliert Typinformationen- Generics: Behält Typinformationen bei (sicher)
F: Kann ich mehrere Constraints haben?
A: Ja! T extends A & B (Intersection Type)
🎉 Herzlichen Glückwunsch! Sie haben Kapitel 7 abgeschlossen!
