Rendre les suppressions d'erreurs Flow plus spécifiques

Mar 19 2020
Nous améliorons les suppressions d'erreurs Flow afin qu'elles ne masquent pas accidentellement les erreurs. Au cours de l'année à venir, Flow prévoit d'apporter de nombreux changements et améliorations à son système de typage.
Photo de icon0.com provenant de Pexels

Nous améliorons les suppressions d'erreurs Flow afin qu'elles ne masquent pas accidentellement les erreurs.

Au cours de l'année à venir, Flow prévoit d'apporter de nombreux changements et améliorations à son système de typage . L'une des conséquences de cela, cependant, est que vous devrez peut-être ajouter plus de suppressions à votre code à mesure que Flow s'améliore pour trouver les problèmes existants.

Cela peut être un problème car les suppressions de Flow affectent plus que l'erreur d'origine que vous avez l'intention de supprimer. Cela réduit la capacité de Flow à détecter les erreurs. Ceci est le résultat de deux propriétés: premièrement, les suppressions de flux peuvent être localisées à n'importe quelle partie d'une erreur de type, et deuxièmement, les suppressions de flux peuvent supprimer tout type d'erreur de type . Pour corriger ces lacunes, nous allons exiger que les suppressions soient placées à l'emplacement de votre code où l'erreur se produit réellement, et qu'elles incluent un code d'erreur spécifiant le type d'erreur que vous souhaitez supprimer.

Pour comprendre ce que tout cela signifie, explorons la nature des erreurs de type Flow.

Qu'est-ce qu'une erreur de type?

Lorsque Flow rencontre un problème lors de la vérification de votre code, comme une incompatibilité entre deux types ou un accès à une propriété non valide, il génère une erreur qui signale à l'utilisateur précisément ce qui ne va pas avec son code. Ces erreurs peuvent contenir une grande variété d'informations en fonction des circonstances particulières qui les ont provoquées, mais les deux qui nous intéressent le plus sont le type d'erreur et les emplacements de l'erreur.

Le type d'erreur encode la nature spécifique du mauvais comportement détecté par Flow dans votre code, qu'il s'agisse de quelque chose de simple comme passer trop d'arguments à une fonction ou de quelque chose de complexe comme la diffusion d'un type d'union. Ces informations indiquent à Flow exactement le type d'informations à afficher à l'utilisateur pour expliquer au mieux exactement où vous vous êtes trompé.

Les emplacements de l'erreur contiennent des informations sur l'emplacement de l'erreur dans votre code. Une erreur peut contenir deux types d'emplacements, un emplacement principal (dont il ne peut y avoir qu'un seul) et des emplacements secondaires , dont il peut y en avoir plusieurs ou aucun. L'emplacement principal correspond à peu près à l'emplacement dans votre code où l'erreur s'est réellement produite, tandis que les emplacements secondaires contiennent des informations sur les sites de définition des types et des valeurs impliqués dans l'erreur. Par exemple:

function foo(x : number) : void {}
foo("hello");
/* error */
foo("hello");
       ^ Cannot call `foo` with `"hello"` bound to `x` because string [1] is incompatible with number [2].
References:
2: foo("hello");
       ^ [1]
1: function foo(x : number) : void {}
                    ^ [2]

function foo(x : number) : void {}
let y : string = "hello";
foo(y);
/* error */
foo(y);
       ^ Cannot call `foo` with `y` bound to `x` because string [1] is incompatible with number [2].
References:
2: let y : string = "hello";
           ^ [1]
1: function foo(x : number) : void {}
                    ^ [2]

Alors, qu'est-ce qui ne va pas avec les suppressions?

Eh bien, étant donné que les suppressions peuvent être appliquées à la fois aux emplacements principal et secondaire, mettre un //$FlowFixMecommentaire au-dessus de la définition de foosupprimerait les erreurs dans les deux exemples ci-dessus. Puisqu'apparaît foocomme un emplacement secondaire dans chaque erreur qui l'utilise, cela signifierait que toute utilisation de foocela entraîne une erreur serait supprimée par cette suppression, partout où elle pourrait se produire. Vous foopourriez appeler avec n'importe quel nombre d'arguments de n'importe quel type et Flow ne vous ferait apparaître aucune erreur ou avertissement à ce sujet. Cela dégrade la confiance des utilisateurs dans la vérification de type de Flow et permet aux bogues qu'il aurait autrement détectés de passer en production.

En plus de cela, les suppressions de Flow affectent toutes sortes d'erreurs, à condition qu'elles contiennent un emplacement couvert par la suppression. Cela signifie que plusieurs erreurs de différents types peuvent être supprimées par une seule suppression. Pour voir le danger dans ceci, considérez l'exemple suivant:

// library file lib.js
function foo(x : number) : void {}
// impl file
const {foo} = require("lib.js");
let y : string = "hello";
// $FlowFixMe
foo(y);

Qu'allons-nous faire à ce sujet?

Pour résoudre ce problème, nous allons apporter les modifications suivantes:

  • Appliquer les emplacements principaux. Nous allons modifier le comportement de suppression de sorte que les suppressions ne s'appliquent qu'aux erreurs lorsqu'elles sont placées à leur emplacement principal. Par exemple, au lieu de vous permettre de supprimer un appel invalide à la définition de la fonction, nous allons maintenant exiger que la suppression soit localisée sur le site d'appel lui-même. De cette façon, Flow sera toujours en mesure de vous alerter sur d'autres appels éventuellement non valides à la fonction.
  • Ajoutez des codes d'erreur. Nous ajouterons également des codes d'erreur à nos suppressions afin qu'ils ne suppriment que les erreurs du type spécifié. Cela empêchera les suppressions de supprimer de manière inattendue un type d'erreur que vous ne vous attendiez pas à rencontrer.
  • Normaliser la syntaxe de suppression. Auparavant, la syntaxe acceptable pour une suppression d'erreur pouvait être configurée manuellement dans le .flowconfigpour un projet donné, permettant une syntaxe de suppression incohérente entre les projets. Dans le cadre des changements ci-dessus, nous normaliserons également la syntaxe de suppression; ne supportant que les formats $FlowFixMe[incompatible-type]ou $FlowExpectedError[incompatible-type].

Sortir

Nous reconnaissons que ce changement peut entraîner l'invalidité d'un nombre important d'erreurs dans vos bases de code, en particulier si vous aviez l'habitude de placer des suppressions dans le code de la bibliothèque. Pour alléger ce fardeau, nous avons quelques suggestions:

  • Pour déplacer vos suppressions nouvellement non valides vers leurs emplacements principaux, nous vous recommandons une combinaison des utilitaires add-commentset remove-commentsfournis dans l'outil Flow. L'exécution ./tool remove-commentssupprimera tous les commentaires qui ne suppriment plus une erreur car ils ne se trouvent pas sur un emplacement principal et ./tool add-commentsplacera de nouvelles suppressions sur des emplacements non supprimés. Le ./toolscript est accessible en clonant le référentiel Flow sur GitHub.
  • Les suppressions sans codes d'erreur continueront de supprimer toutes les erreurs sur leur emplacement, mais une fois que nous avons déployé la fonction de codes d'erreur, vous pouvez ajouter les codes appropriés à votre base de code via un processus similaire à celui ci-dessus. La suppression de tous vos anciens commentaires et leur réajout avec add-commentsinclura le code d'erreur dans le commentaire nouvellement ajouté.