Der Fluch der ausgelassenen Parameter in TypeScript
\nHaben Sie jemals eine Funktion mit zehn optionalen Parametern geschrieben und dann versucht, nur den fünften und zehnten zu übergeben? Und sofort einen Kompilierungsfehler oder, noch schlimmer, einen stillen logischen Fehler erhalten? Kommt Ihnen bekannt vor?
\nAuf Stack Overflow hat diese Frage Tausende von Aufrufen gesammelt. TypeScript-Entwickler stolpern ständig über denselben Hürden: Wie übergibt man einen optionalen Parameter, während man einen anderen auslässt? Die Standardsyntax erlaubt dies nicht – Parameter werden nach Position und nicht nach Namen übergeben.
\nHeute werden wir uns ein für alle Mal mit diesem Schmerz befassen. Ich zeige Ihnen 4 funktionierende Methoden, um das Problem zu lösen: von einfachem Refactoring bis hin zu fortgeschrittenen Techniken mit partial-Objekten. Los geht's!
\n\nWarum ist das überhaupt ein Problem? Der Positionsfluch
\nIn TypeScript (wie auch in JavaScript) werden Funktionsparameter der Reihe nach übergeben. Wenn Sie eine Funktion haben:
\nfunction createUser(\n name: string,\n age?: number,\n email?: string,\n isAdmin?: boolean\n) { /* ... */ }\nSie können sie nicht so aufrufen: createUser('John', , 'john@mail.com'). Das Auslassen eines Parameters hinterlässt eine Lücke, die TypeScript nicht verdaut. Sie müssten undefined oder null übergeben, was den Code und die Logik verschmutzt.
Es gibt aber auch gute Nachrichten: Wir können diese Einschränkung mit mehreren eleganten Methoden umgehen. Lassen Sie uns jede durchgehen.
\n\nMethode 1: Parameterobjekt (die beste Lösung)
\nDies ist das empfohlene Muster in ernsthaften Projekten. Anstelle einer Reihe von Positionsparametern verwenden wir ein einzelnes Objekt mit optionalen Feldern:
\ninterface UserOptions {\n name: string;\n age?: number;\n email?: string;\n isAdmin?: boolean;\n}\n\nfunction createUser(options: UserOptions): void {\n const { name, age, email, isAdmin } = options;\n console.log(`Benutzer ${name} erstellt, Alter: ${age ?? 'nicht angegeben'}`);\n}\n\n// Jetzt kann nur das Nötigste übergeben werden!\ncreateUser({ name: 'Anna', email: 'anna@mail.com' });\ncreateUser({ name: 'Peter', isAdmin: true });\n\nDie Vorteile liegen auf der Hand:
\n- \n
- Egal wie viele Parameter – wir übergeben nur das, was benötigt wird \n
- Der Code ist selbstdokumentierend: Man sieht sofort, wofür was zuständig ist \n
- Einfaches Hinzufügen neuer Felder ohne Änderung der Signatur \n
Dieser Ansatz löst 90% der Probleme mit optionalen Parametern. Aber wenn Sie mit Legacy-Code arbeiten oder die API nicht ändern können – lesen Sie weiter.
\n\nMethode 2: Funktionsüberladung (function overloading)
\nTypeScript erlaubt es, mehrere Signaturen für eine Funktion zu deklarieren. Dies ist praktisch, wenn Sie bestimmte Kombinationen von Parametern haben:
\n// Überladungen deklarieren\nfunction getData(url: string): Promise<any>;\nfunction getData(url: string, timeout: number): Promise<any>;\nfunction getData(url: string, timeout: number, retries: number): Promise<any>;\n\n// Implementierung (muss die allgemeinste sein)\nfunction getData(\n url: string,\n timeout?: number,\n retries?: number\n): Promise<any> {\n // Logik\n return fetch(url, { signal: AbortSignal.timeout(timeout ?? 5000) });\n}\n\n// Jetzt kann man so aufrufen:\ngetData('/api/users'); // timeout = 5000 (Standard)\ngetData('/api/users', 3000); // timeout = 3000\n// So geht es jedoch nicht (Auslassen von timeout ohne Überladung nicht erlaubt):\n// getData('/api/users', undefined, 2); // schlecht\n\nNachteil: Überladungen lösen das Problem des Auslassens von mittleren Parametern nicht. Sie bieten nur strenge Kombinationen. Für flexible Übergabe ist die erste Methode besser.
\n\nMethode 3: Rest-Parameter + Destrukturierung (exotisch)
\nWenn Sie die Positionsabhängigkeit beibehalten, aber Flexibilität hinzufügen möchten, können Sie Tupel mit Rest verwenden:
\ntype OptionalParams = [number, string?, boolean?];\n\nfunction processData(\n required: string,\n ...opt