ProgrammationDéveloppeur Frontend

Comment fonctionne le mécanisme de typage de this dans les méthodes des classes TypeScript lors de l'utilisation de fonctions classiques et de fonctions fléchées ? Décrivez les pièges et les meilleures pratiques.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Dans TypeScript, pour les méthodes au sein d'une classe, le type de this par défaut correspond à l'instance actuelle de la classe. Cependant, si les méthodes sont définies à l'aide de fonctions fléchées, le contexte de this sera lié au moment de la déclaration, et non à l'appel.

Méthode classique :

class Counter { value = 0; increment() { this.value++; } }

Fonction fléchée :

class Counter { value = 0; increment = () => { this.value++; } }

Détails :

  • Les méthodes classiques perdent le contexte de this lorsqu'elles sont passées en tant que callbacks (par exemple, dans des listeners d'événements).
  • Les fonctions fléchées conservent le contexte de la classe déclarée, mais ne sont pas visibles dans le prototype, et sont créées pour chaque instance.
  • Il est possible de spécifier explicitement le type de this dans la signature de la méthode pour une vérification supplémentaire :
class Foo { bar(this: Foo) { // ... } }

Question piège.

Quelle est la différence entre increment() et increment = () => {} dans une classe ? Comment cela affecte-t-il le contexte de this lorsqu'il est utilisé en tant que callback ?

Mauvaise réponse :

  • "Il n'y a pas de différence entre un champ de classe et une méthode, TypeScript comprend tout tout seul."

Bonne réponse :

  • Pour une méthode classique, le contexte de this est déterminé au moment de l'appel. Si vous passez la méthode en tant que fonction : setTimeout(counter.increment, 0), alors this deviendra undefined (en mode strict) ou window (en mode non strict), tandis que la fonction fléchée conservera son environnement :
class Demo { value = 1; inc() { console.log(this.value); } incArrow = () => { console.log(this.value); } } const d = new Demo(); setTimeout(d.inc, 0); // undefined ou erreur setTimeout(d.incArrow, 0); // 1

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


Histoire

Dans un projet avec des frameworks réactifs, les méthodes de classe étaient passées directement comme callbacks sans bind explicite. En conséquence, this devenait undefined, et l'application plantait avec une erreur lors de l'accès aux propriétés de this. Le problème a été résolu en réécrivant les méthodes en fléchées ou avec un bind explicite.


Histoire

Un développeur a explicitement spécifié le type de this dans la méthode, mais a oublié de le typiser à l'intérieur de la fonction fléchée à l'intérieur de cette méthode. Cela a conduit à ce que this dans le callback imbriqué pointe sur window au lieu de l'instance de la classe. L'équipe a rencontré une fuite d'état et a dû réorganiser l'architecture des événements.


Histoire

Un grand composant UI ralentissait l'application, car toutes les méthodes étaient décrites comme des champs fléchés de classe (new Counter().increment = ...), ce qui créait de nouvelles copies de fonctions pour chaque instance au lieu d'une seule définition dans le prototype, comme avec une méthode classique. Cela a entraîné une augmentation de la consommation de mémoire et une nécessité d'optimisation.