Einführung in TypeScript Generics
TypeScript ist eine streng typisierte Programmiersprache, die JavaScript um statische Typisierung erweitert. Eine der leistungsstärksten und oft unterschätzten Funktionen von TypeScript sind Generics (generische Typen). Wenn Sie jemals eine Funktion geschrieben haben, die mit verschiedenen Datentypen arbeiten soll, oder eine Komponente erstellt haben, die universell einsetzbar sein soll, dann sind Generics genau das Richtige für Sie.
In diesem Artikel werden wir im Detail besprechen, was Generics in TypeScript sind, warum sie benötigt werden und wie man sie in der Praxis einsetzt. Sie werden lernen, wie Sie Ihren Code flexibler, sicherer und wiederverwendbarer machen können.
Was sind Generics und warum werden sie benötigt?
Generics (generische Typen) sind ein Mechanismus, der es ermöglicht, Komponenten (Funktionen, Klassen, Interfaces) zu erstellen, die mit verschiedenen Datentypen arbeiten, ohne dabei die Typinformationen zu verlieren. Stellen Sie sich vor, Sie schreiben eine Funktion, die das erste Element eines Arrays zurückgibt. Ohne Generics müssten Sie den Typ any verwenden, was Sie um die Vorteile der strengen Typisierung bringt.
Warum Generics verwenden?
- Typsicherheit: TypeScript überprüft Typen zur Kompilierzeit und verhindert so Fehler.
- Code-Wiederverwendung: Eine Funktion oder Klasse kann mit beliebigen Datentypen arbeiten.
- Verbesserte Lesbarkeit: Der Code wird verständlicher und selbstdokumentierend.
- Reduzierung von Duplikaten: Sie müssen keine separaten Funktionen für jeden Datentyp schreiben.
Ohne Generics würden Sie so etwas schreiben:
// Schlecht: Typinformationen gehen verlorenfunction getFirstElement(arr: any[]): any { return arr[0];}
const num = getFirstElement([1, 2, 3]); // Typ anyconsole.log(num.toUpperCase()); // Laufzeitfehler!Mit Generics wird der Code sicher und flexibel:
// Gut: Typ wird beibehaltenfunction getFirstElement<T>(arr: T[]): T | undefined { return arr[0];}
const num = getFirstElement([1, 2, 3]); // Typ numberconst str = getFirstElement(['a', 'b', 'c']); // Typ string
// num.toUpperCase(); // Kompilierfehler! number hat keine Methode toUpperCaseGrundlagen der Generics-Syntax
Syntax mit spitzen Klammern
Generics verwenden spitze Klammern <>, um Typparameter anzugeben. Üblicherweise werden Parameter mit einem einzelnen Buchstaben bezeichnet: T (Type), U, V usw. Sie können jedoch auch beliebige aussagekräftige Namen verwenden.
// Einfachstes Beispiel: Funktion mit einem Typparameterfunction identity<T>(arg: T): T { return arg;}
// Explizite Typangabelet result1 = identity<string>('Hallo');
// Typinferenz (TypeScript bestimmt den Typ selbst)let result2 = identity(42); // Typ numberMehrere Typparameter
Sie können mehrere Typparameter in einer Funktion oder Klasse verwenden:
function merge<T, U>(obj1: T, obj2: U): T & U { return { ...obj1, ...obj2 };}
const merged = merge({ name: 'John' }, { age: 30 });// Typ: { name: string } & { age: number }console.log(merged.name); // Johnconsole.log(merged.age); // 30Einschränkungen (Constraints)
Manchmal müssen die Typen eingeschränkt werden, die an einen Generic übergeben werden können. Dafür wird das Schlüsselwort extends verwendet:
interface HasLength { length: number;}
// Die Funktion funktioniert nur mit Typen, die eine length-Eigenschaft habenfunction logLength<T extends HasLength>(arg: T): T { console.log(arg.length); return arg;}
logLength('Hallo'); // Funktioniert: 5logLength([1, 2, 3]); // Funktioniert: 3// logLength(123); // Fehler! number hat kein length