ProgrammationDéveloppeur Frontend

Comment typer correctement une fonction de rappel (callback) en TypeScript et quels pièges faut-il éviter en travaillant avec le contexte et les erreurs de type ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question : En JavaScript, les fonctions de rappel sont omniprésentes, mais leurs signatures sont souvent peu claires. En TypeScript, il est important d'indiquer explicitement les types des paramètres et la valeur de retour, sinon il est facile de créer des failles dans la sécurité des types.

Problème : Une typisation incorrecte ou laxiste des callbacks conduit à des types d'arguments et de résultats indéfinis, complique le travail avec le contexte (this), casse la vérification automatique des erreurs par le compilateur et rend le refactoring difficile.

Solution : Il est nécessaire de définir clairement le type de la fonction de rappel, d'indiquer les types des paramètres passés, de gérer correctement les arguments optionnels et la valeur de retour, et, si nécessaire, de spécifier explicitement le type du contexte.

Exemple de code :

type Callback = (error: Error | null, result?: string) => void; function doAsyncWork(data: string, cb: Callback): void { setTimeout(() => { if (data === '') cb(new Error('Chaîne vide')); else cb(null, data.toUpperCase()); }, 100); }

Caractéristiques clés :

  • Indiquez toujours les types de tous les paramètres du callback.
  • Décrivez le type de retour, même si c'est void.
  • Si nécessaire, spécifiez explicitement le type de this (par exemple, via une fonction avec contexte).

Questions piégeuses.

Que se passe-t-il si je ne spécifie pas le type de retour du callback ?

TypeScript acceptera n'importe quel type de retour (par exemple, undefined, void, Promise), ce qui peut entraîner des surprises dans des chaînes asynchrones ou lors du retour de valeurs "par défaut".

type BadCallback = (data: string) => any; // n'importe quel résultat, absence de contrôle

Est-il acceptable d'écrire un callback comme Function ou (...args: any[]) => any ?

Non. Cela supprime toute protection de type, perdant ainsi les informations sur le nombre de paramètres, leurs types et le type de retour. Cette approche coûte plus cher que de renoncer complètement à TypeScript.

Comment typer une fonction avec le contexte this ?

Utilisez le premier paramètre this dans la signature de la fonction ou le cast via bind. Par exemple :

interface ClickCallback { (this: HTMLElement, event: MouseEvent): void; } const handler: ClickCallback = function (event) { this.textContent = 'ok'; };

Erreurs de type et anti-patterns

  • Callbacks non typés (any ou Function)
  • Absence de type de retour dans la signature de la fonction
  • Le non-respect du type this entraîne des erreurs d'exécution aléatoires

Exemple de la vie réelle

Cas négatif

Dans le projet, le callback a été déclaré comme (...args: any[]) => any. Lorsque la logique métier a été mise à jour, la signature a changé, le callback a cessé de transmettre les arguments nécessaires, et les bugs n'ont été découverts qu'en production.

Avantages :

  • Plus facile de compiler et d'intégrer du code tiers

Inconvénients :

  • Aucune protection au niveau des types
  • Difficultés lors des mises à jour

Cas positif

Des types stricts ont été introduits : les interfaces des callbacks ont été décrites, le type de this et le type de retour ont été clairement spécifiés. Le compilateur a commencé à détecter les erreurs avant le déploiement, et le refactoring ainsi que le support pour le dépannage ont été simplifiés.

Avantages :

  • Sécurité des types
  • Vérification des changements de signatures à la compilation

Inconvénients :

  • Typage légèrement plus compliqué, augmentation du volume de boilerplate