Des tests de performance du compilateur Go de TypeScript 7 sur une application Next.js réelle.
Une comparaison pratique des temps d’exécution de tsc entre TypeScript 6 et 7 sur une base de code Next.js réelle, incluant un bug lié à des incohérences dans les tests automatisés et des conseils pour l’upgrade.
Mêmes 412 fichiers, vérifiés deux fois sous deux versions différentes de compilateur. Avec TypeScript 6, la vérification a pris 3,8 secondes. Avec TypeScript 7, elle n’a nécessité que 0,41 seconde. Le vérificateur de types utilisé est fonctionnellement identique en sous-main.
Le chiffre publié par Microsoft indique une accélération de 8 à 12 fois mesurée dans VS Code. Ce qui compte ici, c’est ce que tsc --extendedDiagnostics affiche pour un répertoire donné. Un job CI qui était auparavant bloqué à cause d’une étape de génération Prisma échouée ne devient pas soudainement dix fois plus rapide dans son ensemble simplement parce que le vérificateur de types s’est accéléré ; seule cette étape devient plus rapide. Tout le reste du pipeline reste exactement aussi lent qu’avant.
Ouvrez un terminal.
Sautez l’étape next dev. Allez directement au vérificateur lui-même, en exécutant depuis la racine de l’application :
pnpm exec tsc --noEmit --extendedDiagnostics
Prêtez attention à la valeur Check time qu’il affiche. Cette seule ligne représente la seule mesure qui vaille la peine d’être suivie jusqu’à la fin.
Microsoft a publié TypeScript 7.0 le 8 juillet 2026. Le système de types lui-même n’a pas changé, et le binaire du compilateur s’appelle toujours tsc, mais il s’agit désormais d’une version du compilateur écrite en Go. Le tableau présenté dans l’annonce de la version 1.0 montre que le temps d’analyse de VS Code est passé de 125,7 secondes à 10,6 secondes. Ce chiffre concerne le propre codebase de Microsoft, et non un projet Next.js typique.
Ce qui est vraiment utile, c’est le nombre équivalent pour une petite application Next.js à quatre routes déjà testée sur tous les autres aspects, ainsi que le chiffre correspondant : quel est le coût de next build une fois que l’outil de vérification utilisé est le nouveau. Tout aussi important est de documenter le type d’erreur qui apparaît lorsque une demande de pull request automatisée suppose que « plus rapide » et « qui se comporte différemment » signifient la même chose.
Le CI de l’après-midi a menti au sujet d’une erreur de type
Imaginez une équipe qui a mis à jour la dépendance typescript à la version 7 dans une application de facturation un mardi, car un article de blog promettait une accélération 10 fois supérieure. Le CI est passé en vert nettement plus rapidement. Encouragés par cela, des reviewers ont approuvé et fusionné un outil d’aide branded-id qui, il s’est avéré par la suite, ne passait pas les vérifications de type sur l’ordinateur local d’un collègue.
Le outil d’aide s’était compilé sans problème sur CI uniquement parce que CI résolvait encore la version 6 de typescript via une dépendance du workspace racine. Sur la machine locale, en revanche, la version 7 était installée directement. Le système de types lui-même n’avait pas changé — c’est justement l’objectif affirmé par Microsoft — mais le tsconfig sur CI liait typescript à un alias de package, @typescript/typescript6, hérité d’une entrée d’override ajoutée pendant la période de bêta et jamais supprimée.
Ainsi, le véritable problème n’était pas que TypeScript 7 se comportait différemment. Il s’agissait plutôt de deux binaires de compilateur distincts, d’un fichier lockfile incohérent, ainsi que d’un message sur Slack affirmant que « 7 est disponible » alors qu’en réalité ce n’était pas le cas, du moins pas partout.
C’est ainsi que cela s’est présenté en pratique : une demande de fusion intitulée « supprimer les conversions as InvoiceId, 7 est plus strict ». En réalité, TypeScript 7 n’était pas plus strict dans ce cas. Le même commit activait également le paramètre de compilateur erasableSyntaxOnly, ce qui représente un changement de politique complètement distinct et fera l’objet d’une discussion ultérieure. Associer une simple amélioration des performances à un changement de politique comportementale est précisément la manière dont naissent ces mythes.
La solution consiste à diviser un tel commit en deux parties : l’augmentation de version seule, et le changement de politique séparément. Ce n’est qu’alors que les mesures de temps d’exécution ont un sens.
La phrase que Microsoft a réellement publiée
Dans l’annonce officielle de TypeScript 7.0 datée du 8 juillet 2026, Daniel Rosenwasser a décrit cette version comme apportant une exécution de code natif, un traitement multithreadé via de la mémoire partagée, ainsi qu’un ensemble d’optimisations permettant généralement des accélérations allant de 8 à 12 fois sur les builds complets.
La partie de cette annonce que la plupart des gens ignorent est celle concernant le fait que le système de types reste inchangé.
D’après l’annonce, la nouvelle implémentation basée sur Go a été reprise de l’implémentation existante grâce à un processus de portage minutieux plutôt que d’être reconstruite à partir de zéro, et son comportement de vérification des types est structuralement identique à celui de TypeScript 6.0.
Il n’y a aucune nouvelle syntaxe dans cette mise à jour. Ce qui a changé, c’est la vitesse d’exécution brute pour la même logique de base. Si des erreurs de type apparaissent après l’augmentation de version, ce n’est pas un comportement attendu — c’est une erreur qui mérite d’être signalée.
Next.js 16.3 a ajouté une documentation indiquant que next build utilisera TypeScript 7 pour sa phase de vérification des types si le projet a TypeScript 7 installé en dépendance directe. Cela vous offre un deuxième point pour mesurer le temps d’exécution, en plus de l’exécution indépendante de tsc.
Les deux chronomètres que j’ai réellement utilisés
Même application de test tout au long. Next.js 16.3, React 19, quatre routes, le tableau des factures, et le paramètre du compilateur désactivé pour cette session afin que les chiffres ne se mélangent pas.
Chronomètre un : tsc --noEmit --extendedDiagnostics. Chronomètre deux : next build, en surveillant la ligne relative à la vérification des types dans son output.
J’ai ajouté TypeScript 7 au projet en tant que dépendance.
pnpm add -D typescript@7
L’exécutable s’appelle toujours tsc. Pendant la phase de prévisualisation, le paquet portait le nom de @typescript/native-preview et son binaire s’appelait tsgo. Cette nomenclature a été abandonnée maintenant que nous sommes en version stable. Si vous tombez sur un gist ou un thread faisant encore référence à tsgo, il décrit la période de prévisualisation, et non l’outil actuel.
Afin de permettre à ces deux versions majeures de coexister sur le disque, Microsoft a publié un paquet complémentaire, @typescript/typescript6. Il expose un binaire tsc6, ce qui permet à la commande régulière tsc de faire référence à la version 7 sans abandonner les équipes ou outils qui dépendent encore de la version 6.
pnpm add -D @typescript/typescript6
Par la suite, on utilise le même tsconfig.json pour les deux :
pnpm exec tsc6 --noEmit --extendedDiagnostics
pnpm exec tsc --noEmit --extendedDiagnostics
Mêmes fichiers sources. Même paramètre strict. Mêmes alias de chemins générés par Next.js lors du démarrage du projet avec create-next-app.
Chaque commande a été exécutée trois fois, et la première exécution a été éliminée, car un cache du système de fichiers ne représente pas une vérification réelle en première occurrence.
À quoi ressemblaient les chiffres dans cette base de code
L’application de test dispose de quatre routes et d’environ 80 fichiers TypeScript appartenant au projet lui-même, en plus des fichiers générés automatiquement par Next.js.
Exécution de TypeScript 6.0 via tsc6, en prenant la médiane des deux exécutions conservées :
- Fichiers vérifiés : 412
- Durée de la vérification : 3,82 secondes
- Durée totale : 4,25 secondes
Exécution de TypeScript 7.0 via tsc, avec la même configuration :
- Fichiers vérifiés : 412
- Durée de la vérification : 0,41 seconde
Cela représente une amélioration d’environ 9 fois uniquement en ce qui concerne le temps de vérification. Pas 12 fois, et loin de la réduction de 125 secondes à 10 secondes parfois citée pour les scénarios VS Code. C’est simplement ce que ce répertoire particulier a produit.
En examinant l’étape de vérification de types à l’intérieur de next build :
- Au niveau 6 : 5,1 seconde
- Au niveau 7 : 1,4 seconde
Tout le reste dans next build — l’assemblage et la génération statique pour les quatre routes — est resté globalement stable. Si votre pipeline CI exécute d’abord le linting, puis la vérification de types, ensuite la compilation, et enfin des tests intégraux, la partie de vérification de types a nettement diminué, mais la partie des tests intégraux ne présente aucune amélioration notable.
Un deuxième projet, lourd de schémas Zod et comptant environ 300 fichiers contenant de la logique de validation et des gestionnaires, a montré une amélioration plus importante :
- Durée du contrôle de la version 6 : 11,4 secondes
- Durée du contrôle de la version 7 : 1,3 seconde
Un code contenant beaucoup de types semble entraîner une amélioration relative plus importante. Un petit site de marketing avec une douzaine de fichiers ne montrerait pas d’acceleration proche de 10 fois, simplement parce qu’il n’y a presque rien pour que l’outil d’analyse puisse travailler.
Le bug apparu après la mise à niveau
Ce n’était pas un changement dans le comportement du contrôle des types — c’était un problème lié aux outils utilisés.
eslint-plugin-react-hooks lançait encore typescript via sa propriété parserOptions.project. Cela fonctionnait bien sous la version 7, mais cela ne marchait plus pendant les mois de bêta préliminaire de tsgo. Un bloc parserOptions obsolète indiquait toujours un fichier tsconfig.eslint.json distinct, celui-ci définissant "compilerOptions": { "strict": false } afin d’éviter que les tests anciens ne signalent des erreurs.
CI utilisait cette configuration simplifiée pour le linting, tandis que tsc utilisait la configuration réelle du projet. Deux sources de vérité différentes. En conséquence, une incohérence liée à noImplicitAny est restée inaperçue au sein d’une utilité de test, invisible pour le linting. Lorsque la version 7 a rendu l’exécution de tsc suffisamment rapide pour être lancée en permanence, j’ai ajouté tsc --noEmit directement aux vérifications des pull requests et j’ai complètement supprimé la configuration tsconfig affaiblie réservée uniquement à ESLint.
{
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "biome check .",
"ci": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
}
}
La véritable correction n’était pas spectaculaire. L’histoire qui circulait était que « la version 7 a cassé nos types ». Ce n’était pas le cas ; c’était la configuration dupliquée qui en était responsable.
Vérifier ce qui s’exécute réellement sur votre machine
pnpm exec tsc -v
Vous cherchez Version 7.x dans les résultats. Si le chiffre indiqué reste 5 ou 6, votre espace de travail charge une copie obsolète provenant d’un endroit inconnu. Dans un monorepo pnpm, which vous mènera au mauvais endroit, tandis que pnpm exec ne le fera pas.
Exécutez les diagnostics trois fois séparément, et jetez le résultat de la première exécution.
pnpm exec tsc --noEmit --extendedDiagnostics
Les champs à surveiller dans ces résultats sont : le nombre de fichiers traités, la part du code provenant des bibliothèques, la part provenant des définitions de types, la part correspondant à votre propre code source, ainsi que la durée du contrôle et la durée totale.
Installez maintenant la version 6 à côté de la version 7 et pointez-la vers le même ensemble de fichiers.
pnpm add -D @typescript/typescript6
pnpm exec tsc6 --noEmit --extendedDiagnostics
Dans une base de code comptant des centaines de fichiers, si la durée du contrôle ne diminue pas d’un multiple significatif, soit vous n’ utilisez pas réellement la version 7, soit votre échantillon est trop petit — une douzaine de fichiers ne vous révéleront rien.
Il est également utile d’exécuter next build deux fois, une fois pour chaque binaire, et de ne noter que la ligne relative au contrôle de type à chaque fois. Ne combinez pas toute la durée de compilation dans une analyse de la vitesse de TypeScript — Turbopack est un système distinct qui effectue des tâches séparées.
Si vous rencontrez une erreur de type qui apparaît sous la version 7 mais pas sous la version 6, avec un tsconfig identique, signalez-la. Cela sort du cadre de ce qui est abordé ici. Selon Microsoft, la logique de vérification reste structurellement inchangée, donc un tel écart constitue une erreur, et non un coût de migration attendu.
D’où provient réellement cette vitesse
L’amélioration réside dans le vérificateur lui-même. Le parsing et la liaison sont également devenus plus rapides, mais c’est la durée du vérification qui apparaît dans les journaux de CI et que les utilisateurs ressentent réellement.
La réactivité de l’éditeur est une autre histoire — elle dépend du service linguistique, et non du compilateur indépendant. Dans le tableau des factures, les actions de navigation comme « aller à la définition » semblaient subjectivement plus rapides. Aucun enregistrement du temps de frappe n’a été effectué, donc il n’y a pas ici de tableau des millisecondes.
next dev et son cycle de Fast Refresh ne sont pas devenus considérablement plus rapides grâce à ce changement, car Fast Refresh n’a jamais été bloqué lors d’une exécution complète de tsc à l’origine.
C’est surtout utile avec des agents ou des boucles automatisées qui déclenchent tsc --noEmit après chaque fichier qu’elles modifient. La boucle s’exécute désormais suffisamment rapidement pour que l’omission de cette vérification cesse d’être un raccourci tentant. C’est là l’avantage réel, bien que non annoncé. L’agent qui continue d’écrire des enums simples au lieu d’objets as const est simplement informé plus rapidement de ce changement.
Évaluation du coût réel
Installation : une simple mise à jour d’une dépendance, ainsi que la suppression d’un script tsgo obsolète qui n’était plus nécessaire.
Impact sur le CI : dans l’application principale, l’étape de vérification des types est passée de 3,8 secondes à 0,4 seconde ; dans l’arborescence des workers, elle est descendue de 11,4 secondes à 1,3 seconde. Les huit minutes restantes du pipeline n’ont pas été affectées.
Prix des rumeurs : une demande de fusion a attribué la régression à la version 7, alors qu’elle était en réalité causée par un changement de paramètre intégré dans le même commit. Gardez ces commits séparés.
Expérience utilisateur : une amélioration agréable, mais pas suffisante pour être quantifiée par un chiffre dans les commentaires.
Dénomination : tsc fait désormais référence à la version 7, et tsc6 sert de solution de repli. Si les deux binaires se trouvent sur votre PATH, précisez-le clairement dans le README afin que personne ne se trompe par la suite.
Faut-il passer à la version 7 ou rester sur 6 ?
Passez à la version 7. Le comportement de vérification des types reste identique, le moteur étant simplement plus rapide — il n’y a aucune nouvelle syntaxe à apprendre en supplément.
Ne restez que sur la version 6 si un plugin spécifique, dont vous connaissez le nom, n’a pas encore ajouté de support pour la version 7. Indiquez directement le nom de ce plugin dans votre référence de version. « Attendre que les choses se stabilisent » ne constitue pas à lui seul une raison valable.
Ne combinez pas la mise à jour vers la version 7 avec une modification erasableSyntaxOnly dans la même demande de fusion — si quelque chose ne fonctionne plus, vous ne pourrez pas déterminer quelle modification en est la cause.
Et n’ôtez pas l’option tsc --noEmit de votre pipeline CI juste parce que la version 7 la rend plus rapide. La vitesse est la raison de conserver cette étape, et non celle de l’enlever.
Les limites réelles de cette comparaison
La réduction de 3,82 s à 0,41 s concerne cette application spécifique à quatre routes. La baisse de 11,4 s à 1,3 s provient d’une base de code distincte axée sur les workers. L’amélioration de 8 à 12 fois citée par Microsoft fait référence aux builds complètes sur des répertoires de la taille de VS Code. Personne n’a relancé VS Code ici.
L’expression « structurally identical », datée du 8 juillet 2026, provient directement de l’annonce même de Microsoft. Si les erreurs signalées par votre projet changent réellement après mise à niveau, considérez cela comme un défaut à déclarer, et non comme un effet secondaire anodin à ignorer.
Il n’existe aucun moyen d’inspecter ici le hoisting de vos dépendances. Si pnpm exec tsc -v affiche une version majeure localement tandis que les journaux de votre CI montrent une autre version, vous n’avez pas encore vraiment validé TypeScript 7 — ce que vous avez est un problème de résolution du PATH qui se fait passer pour une comparaison de versions.
Exécutez à trois reprises chacun des programmes tsc6 et tsc. Notez l’heure du contrôle ainsi que le nombre de fichiers générés à chaque exécution. Ces quatre valeurs forment l’ensemble de données brutes que vous pouvez partager si vous souhaitez obtenir des retours concernant votre configuration spécifique.
Une reproduction minimale pour un dossier temporaire
Si vous préférez ne pas modifier votre application réelle pour l’instant, voici le plus petit ensemble d’installations possible qui permet néanmoins de démontrer le problème lié au hoisting.
mkdir ts7-lab && cd ts7-lab
pnpm init
pnpm add -D typescript@7 @typescript/typescript6
echo '{ "compilerOptions": { "strict": true, "noEmit": true } }' > tsconfig.json
echo 'export type InvoiceId = string; export const n: InvoiceId = "inv_1";' > index.ts
pnpm exec tsc -v
pnpm exec tsc6 -v
pnpm exec tsc --extendedDiagnostics
pnpm exec tsc6 --extendedDiagnostics
Notez les chaînes de version ainsi que les heures de contrôle pour les deux versions. Ensuite, ajoutez un package d’espace de travail qui maintienne typescript@6 comme dépendance, et observez ce que pnpm exec tsc -v affiche depuis la racine du répertoire. Ce déséquilibre est précisément le type de problème inattendu que les systèmes CI peuvent vous réserver.
Dans le projet des factures, un autre élément à noter concerne la question de savoir si next build affiche réellement une ligne Finished TypeScript provenant de la version 7. Si cette ligne n’apparaît jamais, c’est que Next.js exécute un vérificateur de types distinct de celui utilisé par votre script typecheck. Il faut aligner ces deux outils : c’est précisément en exécutant deux vérificateurs différents en parallèle que la faille branded-id a pu passer inaperçue lors des vérifications précédentes.
Vérification rapide d’une minute pour les reviewers : ouvrez app/invoices/page.tsx, placez le curseur sur un type searchParams et attendez l’affichage de la description contextuelle. Répétez l’opération pour les versions 6 et 7. Aucun chronomètre n’est nécessaire pour cette vérification ; l’objectif est simplement de s’assurer que le texte affiché en survol ne change pas entre les versions. Même comportement, mais moteur plus rapide en arrière-plan.
Si votre projet dispose d’un fichier tsconfig.eslint.json séparé avec des paramètres assouplis, éliminez-le la même semaine où vous mettez à jour les outils. Un vérificateur de types peu coûteux élimine le prétexte pour que lint utilise des règles différentes de celles utilisées lors de la compilation.
Une mesure à consigner dès le premier jour : exécutez tsc --noEmit --pretty false 2>&1 puis passez le résultat à wc -l, avant et après la mise à jour. Le nombre d’erreurs doit être exactement identique. Dans l’application de facturation, il était zéro dans les deux cas. Pour le projet worker-tree, il s’agissait de quatre erreurs dans chaque cas — mêmes fichiers, mêmes messages à chaque fois. Cette égalité résume vraiment toute l’histoire de la migration. Si les comptes ne correspondent pas, cessez de répéter l’idée du « 10x » et comparez directement les deux fichiers de sortie.
Conservez les deux journaux enregistrés sous /tmp/tsc6.txt et /tmp/tsc7.txt pendant environ une semaine après chaque mise à jour. Supprimez-les une fois que la situation semble stabilisée — mais pas la nuit même où vous déploiez la mise à jour.
Conseils pour celui qui héritera de cette base de code
Exigez que l’output de pnpm exec tsc -v figure dans le modèle de demande de pull request. Si le chiffre affiché n’est pas 7, l’amélioration des performances n’a jamais été véritablement déployée.
N’associez pas cette mise à jour avec erasableSyntaxOnly, verbatimModuleSyntax ou un nettoyage plus complet du tsconfig dans la même modification. Ceux-ci relèvent d’une étape ultérieure. Il s’agit ici uniquement d’un compilateur plus rapide effectuant la même tâche.
Persistez à exécuter tsc --noEmit dans le CI, même si cela coûte désormais presque rien. Cet faible coût est justement l’argument en faveur de son maintien.
Séance de laboratoire, enregistrée en direct : commandes et résultats
Cette section décrit le même laboratoire d’essai des factures à quatre routes utilisé tout au long de cette série. Les versions fixées avant de commencer sont : Node 24, TypeScript 7, Next 16.3.
Ces étapes se trouvent dans le fichier notes/lab.md du répertoire, afin qu’une session future ne dépende pas de la mémoire. Vous pouvez les copier dans l’ordre.
node -v
pnpm exec tsc -v
pnpm exec next --version
Notez les trois numéros de version en haut de votre document. Si l’une des versions majeures ne correspond pas à ce que vous pensez être en cours d’exécution, arrêtez-vous là — tout ce qui suit produira des résultats trompeurs de manière plus subtile.
Vient ensuite l’analyse des routes :
pnpm exec next dev
Visitez /, /invoices, /invoices/1, /settings, puis à nouveau /invoices. Activez l’option « Conserver le journal » dans les outils de développement. Prenez une capture d’écran à la fois de la boîte de filtrage et de la barre d’adresses. Ce duo s’avère être le point de données le plus utile pour un plus grand nombre de vérifications que prévu.
Puis exécutez le vérificateur de types :
pnpm exec tsc --noEmit --pretty false
echo $?
Un code de sortie égal à zéro n’est pas le résultat final — c’est simplement le signal vert pour vérifier le comportement en temps de exécution.
Finalement, c’est de cela qu’il s’agit vraiment dans tout ce texte : exécuter les commandes déjà listées sous « Comment le voir sur votre machine ». Ne les sautez pas juste parce que vous avez déjà vu des chiffres ici — votre machine n’est pas celle d’où proviennent ces chiffres. La chaleur ambiante, un ordinateur portable de 16 GB, ainsi que tout ce que Chrome fait en arrière-plan influenceront davantage les valeurs RSS, le temps de vérification et le délai d’annulation de récupération que n’importe quelle petite mise à jour du framework.
Un autre habitude à conserver : une seule ligne indiquant une « correction échouée » dans la note — une phrase, comme « J’ai essayé X, mais j’ai encore vu Y ». C’est cette ligne qui permet à ce document de rester un rapport fonctionnel plutôt qu’un dossier de présentation parfaitement travaillé. Une suite utile comprend une liste des versions, la commande exacte, les résultats obtenus et la description de la correction échouée. Une capture d’écran du tableau de bord ne suffit pas.
Lectures complémentaires
- Le compilateur Go de TypeScript et l’exécution native : un guide de migration — Découvrez comment le compilateur basé sur Go de TypeScript et l’exécution native Node.js affectent les bases de code React et Next.js, ainsi que ce qu’il convient de corriger dans votre tsconfig dès maintenant.
- À l’intérieur de la réécriture en Go de TypeScript 7 : des gains de vitesse sans modification de code — Apprenez comment le compilateur basé sur Go de TypeScript 7 permet des builds 8 à 12 fois plus rapides, pourquoi ce changement d’architecture fonctionne, et comment mettre à niveau en toute sécurité des projets existants.