À une époque où toute la recherche et la quasi-totalité des nouveaux langages de programmation se tournent vers des compilateurs statiques de plus en plus robustes et stricts, on voit régulièrement émerger le mouvement inverse : des équipes qui font parler de leur produit en revenant dix ans en arrière, abandonnant une codebase TypeScript pour repartir sur du JavaScript sans aucun type. Présenté comme une libération, ce choix mérite qu’on s’y arrête, parce qu’il revient à se priver volontairement de l’un des meilleurs outils dont on dispose aujourd’hui pour produire du logiciel de qualité.
Car TypeScript, avant d’être une affaire de syntaxe ou de mode, c’est d’abord un accélérateur de feedback. Un outil qui favorise la productivité, l’expressivité, l’explicitation des intentions et la découverte du code. Pourquoi s’en priver ? Je n’ai toujours pas saisi les arguments solides qui se dressent contre lui, qu’il s’agisse d’une utilisation directe ou indirecte, par exemple via JSDoc (où, soit dit en passant, c’est bien le moteur de TypeScript qui travaille en coulisses).
Le typage statique comme boucle de feedback
L’essentiel se joue dans le moment où l’on écrit le code, pas après. Un compilateur statique vous dit immédiatement qu’un appel ne correspond pas à la signature attendue, qu’une propriété n’existe pas, qu’un cas n’est pas géré. Ce feedback arrive avant même d’exécuter le programme, avant d’écrire le moindre test, avant le moindre déploiement.
C’est cette immédiateté qui change la nature du travail. Plutôt que de découvrir une erreur au runtime (dans le meilleur des cas en local, dans le pire en production), on la traite à la source, là où le contexte est encore frais et le coût de correction minimal. Le compilateur devient un copilote permanent qui balise le terrain à mesure qu’on avance.
Le vrai test : un refactoring à grande échelle
S’il fallait ne retenir qu’un argument, ce serait celui-là. Il y a quelques jours, j’ai mené sur une codebase TypeScript un refactoring qui touchait plus d’une centaine de fichiers, et je l’ai bouclé en quelques heures seulement. Surtout, je l’ai fait avec une sérénité totale : le compilateur me signalait, fichier après fichier, exactement ce qui restait à mettre à jour, jusqu’à ce que tout soit cohérent.
Je serais curieux de voir quiconque mener le même chantier sur une codebase JavaScript pure, avec la même confiance. En toute franchise, sans TypeScript, je pense que je serais encore en train de serrer les poings, à grep des noms de fonctions, à dérouler mentalement des chemins d’exécution, à espérer ne rien avoir oublié. Le refactoring à grande échelle est précisément l’endroit où l’absence de types se paie le plus cher : chaque modification devient un pari, là où le typage statique en fait une opération mécanique et vérifiable.
« Mais les tests unitaires suffisent »
L’objection revient sans cesse : à quoi bon les types, puisque les tests unitaires vérifient déjà qu’au runtime tout se passe bien ? On me cite alors le bon vieux expect(fn).toHaveBeenCalledWith(...), censé tenir le rôle de garde-fou.
Le problème, c’est qu’on demande là aux tests un travail qui n’est pas le leur. Vérifier qu’une fonction reçoit le bon type d’argument, c’est exactement la raison d’être fondamentale d’un compilateur, autant lui laisser cette tâche, qu’il fait de manière exhaustive et instantanée, sur tous les appels, sans qu’on ait à écrire quoi que ce soit. Mes tests unitaires, eux, je préfère les concentrer là où ils apportent une valeur que le compilateur ne peut pas fournir : vérifier que le système produit bien les résultats métier attendus.
Types et tests ne s’opposent donc pas, ils se répartissent le travail. Le compilateur garantit la cohérence structurelle ; les tests garantissent la justesse du comportement. Faire porter aux seconds la charge des premiers, c’est se condamner à écrire beaucoup plus de tests, pour une couverture pourtant moins complète.
JavaScript n’est pas l’ennemi
Que les choses soient claires : il ne s’agit pas de jeter JavaScript à la poubelle. Il existe des cas d’usage parfaitement légitimes pour du JavaScript pur. Le mainteneur d’une librairie open source qui estime que sa productivité y gagne et que son coût de maintenance y est plus faible a tout à fait le droit de faire ce choix : c’est le sien, et lui seul peut l’arbitrer en connaissance de cause.
Le cas Fastify
L’écosystème Fastify en est un bon exemple : l’intégralité du cœur est écrite en JavaScript. Mais l’histoire ne s’arrête pas là. Fastify est publié avec des fichiers de déclaration (.d.ts) écrits manuellement pour permettre une adoption depuis TypeScript. Et là, on peut légitimement se demander si le coût de maintenance n’est pas, au final, plus élevé : ce sont pratiquement deux codebases conjointes qu’il faut faire progresser en parallèle et maintenir synchronisées.
Le signal le plus parlant vient du créateur lui-même. Matteo Collina, longtemps fervent défenseur du full JavaScript, a récemment reconnu publiquement que son intérêt pour TypeScript ne cessait de grandir, et qu’il éprouvait une réelle satisfaction à en écrire. Venant de lui, l’aveu n’est pas anodin. Et il faut le rappeler : Matteo Collina n’est pas exactement le développeur JavaScript moyen. Si même les meilleurs, sur des projets pensés autour de JavaScript, finissent par y trouver de la valeur, cela en dit long sur la direction du vent.
Conclusion
Pour un projet isolé, maîtrisé de bout en bout par une poignée d’experts, le débat peut rester ouvert. Mais sur une codebase qui grandit, avec plusieurs développeurs aux niveaux variés qui y travaillent activement, avec une exigence de qualité et la volonté d’éliminer toute une classe de bugs avant même l’exécution, il n’y a, à mon sens, pas vraiment matière à hésiter.
Le typage statique n’est pas une contrainte qu’on s’impose : c’est un filet de sécurité qui transforme des paris en certitudes, et des heures d’angoisse en quelques minutes de travail mécanique. La vraie question, au fond, c’est celle-ci : au moment de déployer, préférez-vous vous reposer sur votre compilateur, ou sur une prière ?