Was sind Generics in JavaScript und warum werden sie benötigt?
\n\nStellen Sie sich vor, Sie schreiben eine Funktion, die mit verschiedenen Datentypen arbeiten soll – Zahlen, Zeichenketten, Objekten. Ohne Generics müssten Sie entweder Code duplizieren oder any verwenden und dabei die Kontrolle über die Typen verlieren. Generics sind ein Mechanismus, der es ermöglicht, Komponenten (Funktionen, Klassen, Interfaces) zu erstellen, die mit jedem Datentyp arbeiten, aber dennoch die Typinformationen bewahren.
Obwohl JavaScript eine dynamisch typisierte Sprache ist, wird im Node.js-Ökosystem häufig TypeScript verwendet, das statische Typisierung hinzufügt. Erst in TypeScript entfalten Generics ihre volle Stärke. Dennoch ist es auch für reines JavaScript nützlich, ihre Prinzipien zu verstehen – besonders wenn Sie Bibliotheken schreiben oder mit modernen Frameworks arbeiten.
\n\nIn diesem Artikel behandeln wir:
\n- \n
- Warum Generics benötigt werden \n
- Wie man Generics in TypeScript deklariert und verwendet \n
- Beispiele für Node.js (API, Datenverarbeitung) \n
- Einschränkungen und bewährte Praktiken \n
Grundlagen von Generics: Syntax und einfache Beispiele
\n\nErstes Generic: die identity-Funktion
\n\nEin klassisches Beispiel ist eine Funktion, die das zurückgibt, was sie als Eingabe erhält:
\n\n// Ohne Generics\nfunction identity(value: any): any {\n return value;\n}\n\n// Mit Generics\nfunction identity<T>(value: T): T {\n return value;\n}\n\n// Verwendung\nconst num = identity<number>(42); // num — number\nconst str = identity<string>('hallo'); // str — string\n\n\nDas Symbol <T> ist der Typparameter. Sie können ihn beliebig nennen (T, U, Item), aber traditionell wird T (von Type) verwendet.
Generics mit mehreren Parametern
\n\nManchmal muss man mit mehreren Typen gleichzeitig arbeiten:
\n\nfunction pair<T, U>(first: T, second: U): [T, U] {\n return [first, second];\n}\n\nconst result = pair<number, string>(1, 'eins');\n// result: [number, string]\n\n\nGenerics in Pfeilfunktionen (Node.js)
\n\nIn React oder Hilfsfunktionen werden häufig Pfeilfunktionen mit Generics verwendet:
\n\nconst wrapInArray = <T>(item: T): T[] => {\n return [item];\n};\n\nconst arr = wrapInArray('test'); // arr: string[]\n\n\nAnwendung von Generics in realen Node.js-Projekten
\n\nAPI-Handler mit typisierten Antworten
\n\nStellen Sie sich vor, Sie schreiben eine universelle Funktion für API-Anfragen. Ohne Generics würden Sie die Datentypen verlieren:
\n\n// Schlecht: any\nasync function fetchData(url: string): Promise<any> {\n const response = await fetch(url);\n return response.json();\n}\n\n// Gut: Generics\nasync function fetchData<T>(url: string): Promise<T> {\n const response = await fetch(url);\n return response.json();\n}\n\n// Verwendung\ninterface User {\n id: number;\n name: string;\n}\n\nconst user = await fetchData<User>('/api/user/1');\nconsole.log(user.name); // TypeScript weiß, dass name ein string ist\n\n\nTypisierte Datensammlungen
\n\nBei der Arbeit mit Datenbanken (z. B. über Prisma oder Mongoose) helfen Generics, universelle Repositories zu erstellen:
\n\nclass Repository<T extends { id: number }> {\n private items: T[] = [];\n\n add(item: T): void {\n this.items.push(item);\n }\n\n getById(id: number): T | undefined {\n return this.items.find(item => item.id === id);\n }\n}\n\n// Verwendung\ninterface Product {\n id: number;\n title: string;\n price: number;\n}\n\nconst productRepo = new Repository<Product>();\nproductRepo.add({ id: 1, title: 'Laptop', price: 1000 });\nconst laptop = productRepo.getById(1);\n\n\nWrapper für Fehlerbehandlung
\n\nEine universelle Funktion für