La malédiction des paramètres manqués en TypeScript
\nAvez-vous déjà écrit une fonction avec dix paramètres optionnels, puis essayé de ne transmettre que le cinquième et le dixième ? Et obtenu immédiatement une erreur de compilation ou, pire encore, une erreur logique silencieuse ? Cela vous dit quelque chose ?
\nSur Stack Overflow, cette question a recueilli des milliers de vues. Les développeurs TypeScript trébuchent constamment sur le même râteau : comment transmettre un paramètre optionnel en en sautant un autre ? Car la syntaxe standard ne le permet pas – les paramètres sont transmis par position, et non par nom.
\nAujourd'hui, nous allons une fois pour toutes nous débarrasser de cette douleur. Je vais vous montrer 4 méthodes efficaces pour résoudre le problème : du simple refactoring aux techniques avancées avec des objets partiels. C'est parti !
\n\nPourquoi est-ce un problème ? La malédiction positionnelle
\nEn TypeScript (comme en JavaScript), les paramètres d'une fonction sont transmis dans l'ordre. Si vous avez une fonction :
\nfunction createUser(\n name: string,\n age?: number,\n email?: string,\n isAdmin?: boolean\n) { /* ... */ }\nVous ne pouvez pas l'appeler ainsi : createUser('John', , 'john@mail.com'). Sauter un paramètre laisse un trou que TypeScript ne digère pas. Vous devrez transmettre undefined ou null, ce qui pollue le code et la logique.
Mais il y a une bonne nouvelle : nous pouvons contourner cette limitation de plusieurs manières élégantes. Examinons chacune d'elles.
\n\nMéthode 1 : L'objet de paramètres (la plus correcte)
\nC'est le modèle recommandé dans les projets sérieux. Au lieu d'une multitude de paramètres positionnels, utilisez un seul objet avec des champs optionnels :
\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(`Utilisateur ${name} créé, âge : ${age ?? 'non spécifié'}`);\n}\n\n// Maintenant, on peut ne transmettre que ce qui est nécessaire !\ncreateUser({ name: 'Anna', email: 'anna@mail.com' });\ncreateUser({ name: 'Pierre', isAdmin: true });\n\nLes avantages sont évidents :
\n- \n
- Peu importe le nombre de paramètres – on ne transmet que ce qui est nécessaire \n
- Le code est auto-documenté : on voit immédiatement à quoi correspond chaque élément \n
- Facile d'ajouter de nouveaux champs sans modifier la signature \n
Cette approche résout 90 % des problèmes avec les paramètres optionnels. Mais si vous travaillez avec du code legacy ou ne pouvez pas modifier l'API – lisez la suite.
\n\nMéthode 2 : La surcharge de fonctions (function overloading)
\nTypeScript permet de déclarer plusieurs signatures pour une même fonction. C'est pratique lorsque vous avez des combinaisons spécifiques de paramètres :
\n// Déclaration des surcharges\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// Implémentation (doit être la plus générale)\nfunction getData(\n url: string,\n timeout?: number,\n retries?: number\n): Promise<any> {\n // logique\n return fetch(url, { signal: AbortSignal.timeout(timeout ?? 5000) });\n}\n\n// On peut maintenant appeler ainsi :\ngetData('/api/users'); // timeout = 5000 (par défaut)\ngetData('/api/users', 3000); // timeout = 3000\n// Mais pas comme ceci (sauter timeout est impossible sans surcharge) :\n// getData('/api/users', undefined, 2); // mauvais\n\nInconvénient : les surcharges ne résolvent pas le problème du saut des paramètres intermédiaires. Elles ne fournissent que des combinaisons strictes. Pour une transmission flexible, mieux vaut utiliser la première méthode.
\n\nMéthode 3 : Paramètres rest + déstructuration (exotique)
\nSi vous souhaitez conserver le positionnement tout en ajoutant de la flexibilité, vous pouvez utiliser des tuples avec rest :
\ntype OptionalParams = [number, string?, boolean?];\n\nfunction processData(\n required: string,\n ...opt