ProgrammationDéveloppeur Frontend/Backend

Comment fonctionne l'option Strict Function Types dans TypeScript ? Comment cela affecte-t-il la vérification des types de fonctions avec covariance et contravariance, et dans quels cas une incompatibilité de signature entraînera-t-elle une erreur de compilation ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question

Par défaut, TypeScript permet une certaine "souplesse" dans la correspondance des signatures de types de fonctions, en autorisant les fonctions covariantes et contravariantes à être considérées comme compatibles. À partir de TypeScript 2.6, l'option strictFunctionTypes a été introduite, garantissant une vérification stricte des types de fonctions et empêchant de nombreuses classes d'erreurs, en particulier dans de grandes bases de code.

Problème

Sans vérification stricte, il est possible qu'un gestionnaire de fonction ou un callback prenne un nombre supérieur ou un type de paramètres plus spécifique, ce qui passe inaperçu pour le développeur. Cela conduit à des erreurs d'exécution liées à la covariance des types de retour et à la contravariance des arguments.

Solution

L'option strictFunctionTypes introduit une contravariance stricte pour les types de paramètres de fonction. Désormais, les fonctions ne sont compatibles que si le type source du paramètre est un supertype du paramètre de destination, et non l'inverse.

Exemple de code :

type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // Erreur avec strictFunctionTypes : argument trop spécifique catHandler = animalHandler; // Autorisé, Cat est un sous-type d'Animal

Caractéristiques clés :

  • Les arguments des fonctions sont vérifiés pour la compatibilité des "supertypes" (contravariance)
  • Les valeurs de retour sont vérifiées pour la covariance (sous-types autorisés)
  • La violation des signatures entraîne des erreurs de compilation

Questions pièges.

Était-il possible d'assigner un gestionnaire avec un type de paramètre plus spécifique auparavant, avant l'activation de strictFunctionTypes ?

Oui, avant l'activation de strictFunctionTypes, TypeScript permettait d'assigner des fonctions plus spécifiques à la place de fonctions générales, ce qui entraînait des problèmes d'exécution :

enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // Sans strictFunctionTypes : autorisé

Comment strictFunctionTypes affecte-t-il les callbacks avec des paramètres optionnels ?

Si des paramètres de fonction callback rendent certains paramètres optionnels, la vérification stricte n'autorisera pas l'utilisation d'une fonction avec moins de paramètres obligatoires à un endroit où une fonction avec plus de paramètres est attendue. Cela empêche la situation où le callback ne reçoit pas les données nécessaires.

Y aura-t-il des problèmes de compatibilité lors de l'activation de strictFunctionTypes dans de vieux projets ?

Oui, il y a un risque d'apparition de nouvelles erreurs de compilation, car de nombreuses fonctions et gestionnaires ont pu être assignés les uns aux autres en violation de la contravariance. Cela se produit souvent lors de l'utilisation de callbacks ou d'API de bibliothèques tierces sans typage strict.

Erreurs de types et anti-patterns

  • Utilisation d'un typage obsolète des callbacks sans vérification stricte des paramètres
  • Tentative d'assigner une fonction avec un type de paramètre plus spécifique/étroit à un gestionnaire plus général
  • Ignorer les erreurs lors de l'activation de strictFunctionTypes (commenter l'option au lieu de corriger les types)

Exemple de la vie réelle

Cas négatif

Dans un grand projet, les gestionnaires d'événements acceptent des types plus spécifiques (MouseEvent au lieu du général Event). Cela n'est pas détecté jusqu'à l'activation de l'option stricte, entraînant des erreurs lors de l'exécution avec différentes sources d'événements.

Avantages :

  • Prototypage plus rapide

Inconvénients :

  • Bugs d'exécution en cas d'incompatibilité des types d'événements
  • Débogage difficile après l'extension du code

Cas positif

Le projet utilise strictFunctionTypes depuis le début. Lors de l'ajout de nouveaux gestionnaires, toutes les divergences de types sont automatiquement détectées par le compilateur. Le code devient plus résistant aux erreurs de frappe et est plus facile à maintenir.

Avantages :

  • Fiabilité
  • Sécurité de la transmission des fonctions et gestionnaires
  • Comportement prévisible lors du refactoring

Inconvénients :

  • Nécessite une conception soignée des signatures
  • Dans certains cas, il faut écrire des wrappers ou des surcharges supplémentaires pour la compatibilité