TypeScript typé strictement: le mode strict ne suffit pas

Publié le

Maintenant que TypeScript a été largement adopté, il est temps d’être sérieux et d’aller au bout de la démarche : un code entièrement typé statiquement.

Avertissement

Le but de cet article (disponible en Anglais sur Medium) n’est pas de convaincre qui que ce soit des bénéfices de TypeScript. Il s’adresse à des développeurs qui ont déjà conscience que, JavaScript étant aujourd’hui utilisé pour créer des applications (c’est-à-dire qu’il est en charge du routing / navigation et du templating / affichage des données), une vérification des erreurs est une nécessité, pas juste une option fantaisiste.

De même, j’ai conscience qu’il y a d’autres types d’erreurs que celles qui peuvent être réglées par le typage statique, mais ce n’est pas non plus le sujet de cet article.

Niveau 0 : JavaScript

En JavaScript, nous sommes habitués à coder dans le néant : vous savez, quand l’autocomplétion de l’éditeur ne propose rien, mais que nous continuons à coder malgré tout, en supposant que cela va fonctionner par magie.

Code dans le néant : ~50% (c’est juste pour donner une idée, ce ne sont pas de vraies statistiques).

Niveau 1 : TypeScript en config par défaut

TypeScript est seulement un surensemble de JavaScript (c’est-à-dire pas un langage différent, mais du JavaScript natif standard, facultativement amélioré). Ainsi, par défaut, TypeScript ne demande jamais d’ajouter explicitement des types.

Il essaiera plutôt de déduire les types autant que possible. Le TypeScript d’aujourd’hui est très intelligent : disons qu’il peut deviner environ 80% des types.

Mais TypeScript n’est pas devin :

TypeScript peut déduire le type du deuxième paramètre grâce à la valeur par défaut. Mais le premier sera de type any.

Code dans le néant: ~20%.

Niveau 2 : TypeScript en mode strict

Bien que ce ne soit par la configuration par défaut, la façon recommandée officiellement pour travailler avec TypeScript est en mode strict.

Le mode strict active 2 principales options de compilation :

  • noImplicitAny
  • strictNullChecks

Maintenant, TypeScript demandera d’indiquer quand une valeur peut être null (strictNullChecks), et quel est le type quand la déduction n’est pas possible (noImplicitAny).

Notez que TypeScript ne demande pas d’expliciter le type du second paramètre : il est toujours déduit. C’est pour cela que l’option s’appelle “no implicit any”.

Ainsi, passer en mode strict ne requiert pas un effort supplémentaire gigantesque. Il s’agit juste d’ajouter les types dans environ 20% du code.

Le mode strict sera activé en créant :

  • un projet TypeScript (tsc --init)
  • une application Angular ≥ 9 en mode strict (ng new --strict)
  • une application React (create-react-app --template typescript)
  • une application Vue (vue create avec l’option TypeScript)

Code dans le néant : semble être 0%. Mais il y a un piège : le mode strict n’est pas si strict que cela.

Niveau 3 : any is evil

Le code ci-dessus sera autorisé par la compilation, même en mode strict : les anys explicites sont toujours autorisés par TypeScript.

Les linters peuvent venir à la rescousse. TSLint a une règle no-any. Avec ESLint et la règle @typescript-eslint no-explicit-any

Tout notre code est maintenant typé ! Code dans le néant : 0%.

Mais interdire tous les anys requiert une connaissance un peu plus avancée de TypeScript que les bases.

unknown

Depuis TypeScript 3.0, quand nous ne savons vraiment pas quel est le type d’une donnée, le bon type est unknown, pas any.

Contrairement à any, qui permet de coder dans le néant, unknown fera en sorte que TypeScript nous rappelle que la valeur est vraiment inconnue, et nous forcera donc à la vérifier.

Generics

Dans d’autres cas, le type est connu mais variable : il s’agit des generics.

Niveau bonus : types de retour

Bien que TypeScript devinera toujours le type de retour des fonctions, il le fera sur la base du code. Nous supposons donc, avec un peu trop de confiance, que notre code fait ce qu’il est supposé devoir faire.

Les linters peuvent à nouveau nous venir en aide. TSLint a une règle typedef avec l’option call-signature. Avec ESLint et la règle @typescript-eslint explicit-function-return-type:

Dans tous les cas, indiquer les types des paramètres et du retour des fonctions devrait être la documentation requise minimale.

Niveau framework : Angular strict

Certains frameworks ajoute leur propre étape de compilation, par dessus celle de TypeScript. C’est le cas d’Angular, qui a donc des options de compilation strictes additionnelles :

Découvrez la formation TypeScript