Introduction à Flow.js
publié leFlow
est un analyseur statique de type pour JavaScript, créé par Facebook pour ses projets (comme React ou Jest, 2 excellents outils pour développeur Front). Son principal adversaire et pas le moindre est TypeScript
de Microsoft. Sans entrer dans les détails car ici on ne va parler que de Flow
, TypeScript
est un méta-langage qui englobe JavaScript en lui rajoutant des “options”. La plus connue est le Typage
qui est la partie qui nous intéresse dans cet article. Mais TypeScript
apporte aussi les Annotations/Décorateurs
(qui vont arriver dans ECMAScript 2019 ou 2018 : actuellement en stage2), les futures fonctionnalités définies dans les versions d’ECMAScript
, et un compilateur pour faire fonctionner tout cela dans nos navigateurs actuels.
Flow
n’est donc opposé à TypeScript
que sur une des fonctionnalités de ce dernier, en contrepartie Flow
fonctionne avec JavaScript c’est à dire que vous pouvez l’insérer progressivement sur votre projet qui était démarré avant même que TypeScript
n’existe.
Si vous avez déjà jeté un œil à Flow
, vous pouvez vous arrêtez votre lecture ici car cet article ne vous apportera rien vu qu’il s’agit d’une présentation triviale. Un article plus avancé verra le jour dans les semaines à venir.
Fonctionnement
Pour utiliser Flow
vous avez besoin :
- de l’installer
- de paramétrer votre code
- de l’utiliser
- de nettoyer votre code des paramètres ajoutés pour l’exécution
Basiquement si vous prenez n’importe quel projet JavaScript vous pouvez ajouter la ligne "flow": "flow"
dans la section scripts de votre package.json puis lancer les étapes 1 et 3 :
npm i -D flow-bin
npm run flow init
npm run flow
Et la magie opèrera normalement en ne remontant aucune erreur vue que nous n’avons rien fait pour la partie 2.
PS : L’initialisation n’est bien sur à faire qu’une seule fois.
En mode développement
Il est bien sur hors de question de lancer une commande npm aussi longue (analyse tout le projet à chaque fois) pour chaque sauvegarde et le but même d’un analyseur statique de type est de remonter les erreurs en temps réel dans l’éditeur de texte. Flow
fonctionne donc par analyses incrémentales à partir d’un processus en tache de fond.
npm run flow status
No errors
A partir de maintenant Flow
observe les modifications dans votre projet pour remonter les erreurs. Vous pouvez arrêter le processus avec npm run flow stop
Paramétrer son code
Pour demander à Flow
de contrôler le type d’un fichier il suffit de lui ajouter en commentaire l’annotation @flow
// @flow
// ou
/* @flow */
A partir de maintenant votre fichier est validé par Flow
automatiquement et l’ajout d’un code invalide remontera les erreurs :
// @flow
function square(n) {
return n * n
}
square("a")
Constater l’ampleur des dégats
Flow
propose de valider les fichiers même s’ils ne contiennent pas l’annotation @flow :
npm run flow check --all
Cela permet d’avoir une idée de la longueur du chemin que vous aurez à parcourir pour avoir un projet clean. Sur mon (petit) projet test ça a donné ça :
Found 32 errors
Et oui l’ajout de controle de type à posteriori ne fait pas que du bien, mais c’est justement ce qui est agréable avec Flow
c’est que c’est incrémental.
Utiliser Flow
Flow
utilise beaucoup l’inférence de type pour remonter les 32 erreurs évoquées un peu plus haut, mais il permet aussi de définir des types explicitement :
- Primitive Types : number, string, boolean, null, undefined(void), Symbol
- Literal Types : une forme de validation par énumération de valeurs (2 | 3) n’admet que les valeurs 2 ou 3 et pas les autres nombres
- Any Types: comme en
TypeScript
, à éviter - Maybe Types: Un type optionnel préfixé par ? peut être
null
ouvoid
. - Function Types: signature de méthode = typage des paramètres et de la valeur de retour
- Object Types: Typer les propriétés d’un objet, fonctionne avec l’inférence
- Array Types: Typer la nature du tableau
- Tuple Types: Un Array de taille fixe, et dont les cases sont typées
- Class Types: POO avec héritage, Generics and co
- Type Aliases: l’interface de
TypeScript
(c’est à dire la définition d’un objet dont les props sont typées mais n’admettant pas de méthode) - Interface Types: Les interface comme en Java
- Generic Types: Les Generics/Diamonds comme en Java
- Union Types: énumération de type string | number | Type1
- Module Types: typer l’export, pour que l’import le soit par inférence
Et quelques autres plus marginaux.
En gros Flow
vous apporte une validation qui par inférence va se débrouiller pour trouver le maximum d’erreurs possibles. Il va vous demander de signer vos méthodes quand elle ne le seront pas au moment ou vous allez mettre @flow
dans votre fichier. Et il va vous donner une boite à outil qui vous offre le même contrôle de type que le plus typé de tous les langages objets typés : Java, mais de façon optionnelle.
Enfin pour utiliser tous ces types on utilise le caractère :
oui comme en TypeScript
:
// @flow
var a: number = 2
function square(n: number): number {
return n * n
}
Type Vehicle {
nbWheels: number,
engine: string
}
// ...
Librairies tierces
Comme les typings pour TypeScript
, Flow
demande aux éditeurs de librairies tierces de décrire un fichier flow-typed
pour simplifier la vie des projets utilisant Flow
. Cependant Flow
ne lancera aucune insulte si le fichier flow-typed
n’existe pas, il se contentera d’utiliser l’inférence ce qui conduira à remonter peu d’erreurs.
Nettoyage du code
Vous l’avez surement remarqué à la lecture de cet article, Flow
utilise des syntaxes qui n’ont pas grand chose de valide en JavaScript pour remonter des erreurs à l’analyse statique, maintenant pour fonctionner, pour utiliser concrètement ce code il va falloir rajouter à votre stack de développement (grunt/gulp/browserify/webpack/node/…) une étape de clean-up de Flow
. Il y a des tutos un peu partout pour mettre en place Flow
sur un projet React, un projet Vue, un projet Node, …
#installation
npm i -D babel-cli babel-preset-flow
{
"//": ".babelrc",
"presets": ["flow"]
}
#nettoyage avec résultat dans le dossier lib
npm run babel src/ -d lib/
Conclusion
Flow
est une alternative à TypeScript
pour la partie Typage, il vient avec ses propres contraintes et un avantage : il est beaucoup plus facile de faire de la migration incrémentale de sa base de code JS vers Flow
que vers TypeScript
. En contrepartie il offre moins de fonctionnalités que TypeScript
, et il faudra chercher du coté de Babel pour avoir le même niveau de features (par exemple pour intégrer les Decorators). Flow
se présente comme un simple linter là ou TypeScript
est un outil capable de transformer votre éditeur en IDE. Pour faire simple on a 2 acteurs rendant un service similaire et qui vont probablement activement évoluer pour être le meilleur : saine concurrence. Cette concurrence va permettre d’enrichir les futurs débats du TC39 pour l’arrivée des Types dans ECMAScript (car oui après-demain on aura les Types directement dans le langage: actuellement en stage -1 peut-être même -10)