Accueil / Articles / TypeScript 6's Bridge Role in the Path to a Native TS 7 Compiler

Cet article est publié en anglais.

TypeScriptJavaScriptCompilersNode.jsToolingPerformance

TypeScript 6's Bridge Role in the Path to a Native TS 7 Compiler

Learn how TypeScript 6 updates default configs, module resolution, and import syntax to prepare codebases for the faster, Go-based TypeScript 7 compiler.

2201 mots

Tout développeur qui gère une base de code TypeScript importante connaît ce retard familier : vous appuyez sur enregistrer, et l’éditeur s’arrête pendant quelques secondes tandis que le serveur de langage met à jour les informations. Dans les pipelines CI, les demandes de pull s’accumulent, car la seule vérification des types peut prendre de cinq à dix minutes pour s’achever.

Développeur enregistre le fichier ──> [ tsc basé sur JS : traitement en fil unique ] ──> Retour lent
Développeur enregistre le fichier ──> [ Moteur natif de TS 7 : threads parallèles ] ──> Retour instantané

TypeScript 7 introduit un compilateur natif développé en Go. Il traite les tâches sur plusieurs threads, réduisant ainsi les temps de compilation de 8 à 10 fois. Cependant, on ne peut pas simplement intégrer un compilateur natif multithreadé dans un projet qui dépend encore de paramètres de configuration datant de 2018.

C’est là l’objectif de TypeScript 6 : il sert de point de transition. Il élimine les dettes techniques obsolètes, met à jour les paramètres par défaut périmés et garantit que votre projet se compile sans problème une fois TypeScript 7 disponible.

Pourquoi TypeScript a-t-il besoin d’une version de transition ?

Pendant plus de dix ans, le compilateur TypeScript lui-même a été écrit en TypeScript et exécuté sous Node.js. Cela permettait aux développeurs JavaScript de contribuer directement au code du compilateur.

Le problème, c’est que l’exécution en JavaScript est mono-threadée. À mesure que les bases de code devenaient de plus en plus volumineuses, avec des monorepos contenant des millions de lignes, le compilateur a fini par atteindre ses limites en termes de performance.

TypeScript 7 remédie à cela en exécutant du code machine natif en parallèle sur plusieurs cœurs CPU. Cependant, un compilateur parallélisé introduit deux exigences de comportement qui n’étaient pas importantes auparavant :

  • Ordre déterministe :Même lorsque plusieurs cœurs évaluent des types en même temps, le compilateur doit garantir que les erreurs signalées et les types inférés apparaissent toujours dans une séquence cohérente et reproductible.
  • Conformité aux normes modernes :Soutenir continuellement des systèmes de modules obsolètes datant d’il y a une décennie, tels que AMD, ou des stratégies de résolution dépassées, ajoute une complexité et des coûts inutiles à un compilateur natif.

TypeScript 6 marque le point où l’équipe impose ces exigences. Il incite les développeurs à suivre les conventions actuelles d’ECMAScript afin que le passage ultérieur à la version 7 ne provoque pas de perturbations.

Les plus grandes modifications de configuration dans tsconfig.json

La plupart des changements visibles introduits dans TypeScript 6 se trouvent à l’intérieur de votre tsconfig.json. Plusieurs valeurs par défaut anciennes ont été mises à jour pour refléter la manière dont les projets sont réellement construits aujourd’hui.

1. strict: true est désormais la valeur par défaut

Auparavant, un fichier tsconfig.json vide signifiait que TypeScript fonctionnait en mode permissif, à moins d’activer manuellement "strict": true.

Désormais, avec TypeScript 6, le mode strict est activé automatiquement.

// tsconfig.json
{
 "compilerOptions": {
 // Cela est désormais activé par défaut dans TypeScript 6
 "strict": true
 }
}

Si votre projet disposait déjà de la configuration strict: true, rien ne change pour vous. Mais si votre code dépendait de types implicites any ou de valeurs null et undefined non vérifiées, la mise à niveau fera apparaître immédiatement des erreurs de type.

Pourquoi c’est important :

Un vérificateur de types natif fonctionne le plus efficacement lorsque les informations sur les types sont explicites et cohérentes. Un typage lâche oblige le compilateur à gérer des scénarios imprévisibles, ce qui ralentit l’analyse statique.

2. La cible par défaut des modules est esnext

Historiquement, TypeScript utilisait par défaut des cibles de sortie plus anciennes telles que ES3 ou ES5. En pratique, presque tous les environnements d’exécution utilisés en production aujourd’hui sont à jour : Node.js, Bun, Deno ainsi que les navigateurs modernes prennent tous en charge nativement les modules ECMAScript.

Avec TypeScript 6, l’option module par défaut est désormais esnext, et la valeur par défaut de target fait référence à une version actuelle d’ECMAScript.

// Configuration moderne recommandée
{
 "compilerOptions": {
 "module": "esnext",
 "moduleResolution": "bundler", // ou "nodenext"
 "target": "es2024">
 }
}

Si votre application a encore besoin d’un format CommonJS pour fonctionner sur des environnements serveur plus anciens, vous pouvez toujours définir manuellement "module": "commonjs". TypeScript n’impose plus automatiquement un format de sortie ancien à moins que vous ne le demandiez.

Frontières de modules plus propres : dites adieu aux astuces avec baseUrl

Auparavant, il était courant que les équipes configurent des alias de chemins de cette manière :

// Ancien schéma dans tsconfig.json
{
 "compilerOptions": {
 "baseUrl": "./",
 "paths": {
 "@components/*": ["src/components/*"],
 "@services/*": ["src/services/*"]
 }
 }
}

Les versions plus anciennes de TypeScript exigeaient la présence de baseUrl avant même de pouvoir gérer les mappages paths. Cette exigence créait des difficultés, car baseUrl permettait également aux développeurs d’écrire des imports sans préfixe relatif — comme dans import { Button } from "src/components/Button" — ce qui rendait difficile de distinguer les fichiers locaux du projet des packages téléchargés depuis npm.

TypeScript 6 élimine cette dépendance : paths peut désormais fonctionner de manière indépendante, sans nécessiter de déclaration de baseUrl. De plus, TypeScript 6 ajoute un support natif pour les importations de sous-répertoires dans Node.js, selon la convention utilisant un préfixe #.

Utilisation des importations de sous-répertoires natives

Au lieu de compter sur des alias spécifiques à TypeScript, les projets existants peuvent s’appuyer sur le champ standard imports présent dans package.json :

// package.json
{
 "name": "my-app",
 "imports": {
 "#services/*": "./src/services/*.js",
 "#utils/*": "./src/utils/*.js"
 }
}

Dans vos fichiers sources, vous faites référence à ces sous-répertoires en utilisant la syntaxe standard # :

// src/api/user.ts
import { db } from "#services/database";
import { formatName } from "#utils/string";
export function getUser(id: string) {
 const user = db.find(id);
 return formatName(user.name);
}

Puisque ce mécanisme est compris par Node.js lui-même et ne nécessite aucune réécriture du côté du compilateur, la résolution des fichiers devient nettement plus rapide tant pour TypeScript 6 que pour la prochaine version, TypeScript 7.

Syntaxe de module littérale et imports uniquement de types

Un problème récurrent dans les bases de code qui combinent du code à exécution et des déclarations de types est le fait que les importations contenant uniquement des types puissent être traitées par erreur comme des importations réelles et exécutables. Lorsque vous importez une interface à l’aide d’une instruction import ordinaire, tout outil qui lit ce fichier doit déterminer par lui-même si l’importation contient de la logique JavaScript réelle ou uniquement des informations de type pour le temps de compilation.

TypeScript 6 incite les équipes à activer verbatimModuleSyntax:

// tsconfig.json
{
 "compilerOptions": {
 "verbatimModuleSyntax": true
 }
}

Avec cette option activée, la règle devient sans équivoque : tout ce qui est purement un type doit être importé à l’aide du mot-clé import type.

// AVANT : Le compilateur devait vérifier si User et Order contenaient du code en temps d’exécution
import { User, Order, calculateTotal } from "./billing";
// APRÈS : Procédure explicite et prévisible pour les compilateurs ainsi que les outils de bundling
import { calculateTotal } from "./billing";
import type { User, Order } from "./billing";

Pourquoi est-ce important pour TypeScript 7 ?

Le compilateur multi-cœur et parallélisé à venir tente de traiter les fichiers de manière isolée chaque fois que c’est possible. Une instruction import type lui indique immédiatement qu’aucun élément présent dans ce fichier ne produira de JavaScript, lui permettant ainsi d’éviter d’ouvrir et d’analyser ./billing.ts simplement pour déterminer les règles de génération applicable au fichier actuel. Cette petite discipline contribue à réduire considérablement la charge de compilation sur de grands projets de code.

Nouvelles ergonomies linguistiques intégrées

En plus des paramètres par défaut de configuration, TypeScript 6 intègre quelques fonctionnalités pratiques qui facilitent l’écriture de schémas de code courants.

1. Map.getOrInsert() et Map.getOrInsertComputed()

Pensez à la fréquence à laquelle vous avez dû écrire ce type de logique repetitive de recherche dans le cache :

// La méthode ancienne et répétitive
const userCache = new Map<string, UserProfile>>();
function getProfile(userId: string): UserProfile {
 let profile = userCache.get(userId);

 if (!profile) {
 profile = fetchProfileFromDatabase(userId);
 userCache.set(userId, profile);
 }

 return profile;
}

TypeScript 6 prend en charge la méthode getOrInsertComputed proposée par TC39, vous permettant de remplacer ce schéma par :

// La méthode moderne de TypeScript 6
const userCache = new Map<string, UserProfile>>();
function getProfile(userId: string): UserProfile {
 // La fonction de rappel n’est exécutée que si la clé n’existe pas déjà
 return userCache.getOrInsertComputed(userId, () => {
 return fetchProfileFromDatabase(userId);
 });
}

Cette version est plus compacte, évite le besoin d’une variable de remplacement modifiable et maintient une inférence de type précise en permanence.

2. Types intégrés pour RegExp.escape()

Sanitiser les caractères spéciaux avant de les intégrer dans une expression régulière signifiait autrefois devoir écrire son propre outil d’aide ou d’installer un paquet tiers. TypeScript 6 dispose désormais de définitions de types intégrées pour RegExp.escape():

const userInput = "item.value [test]";
// Échappe de manière sécurisée des caractères tels que '.', '[', et ']'
const safePattern = RegExp.escape(userInput);
const regex = new RegExp(`^${safePattern}

  
    
    
    
    
    Operator Software for Solar, BESS & Video | REACTAPP.TOP
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    TypeScript 6's Bridge Role in the Path to a Native TS 7 Compiler
    
    
    
    
  
  
    
);

Avec cela en place, vous évitez toute une catégorie de bugs d’injection de regex sans ajouter la moindre dépendance à votre projet.

Préparation pour un ordre de types déterministe

Une ajoutation plus discrète mais importante dans TypeScript 6 est le drapeau stableTypeOrdering.

Jusqu’à TypeScript 5.x, l’ordre dans lequel apparaissaient les membres d’un type union dépendait de la séquence dans laquelle le compilateur traitait les fichiers en mémoire. Comme la compilation s’effectuait sur un seul thread, cet ordre restait généralement constant d’une exécution à l’autre.

Cependant, une fois que l’on passe à un compilateur parallélisé comme celui prévu pour TypeScript 7, les threads de travail peuvent terminer le travail qui leur a été assigné dans un ordre différent à chaque fois. Si un thread termine avant un autre, une union peut ressembler à string | number ; en relançant la compilation ou en l’exécutant sur une machine différente, on peut obtenir number | string à la place.

Afin d’éviter que les fichiers .d.ts générés ne changent d’ordre de manière imprévisible, TypeScript 7 applique en interne une règle de tri stricte et déterministe. TypeScript 6 vous permet déjà d’activer ce même comportement :

// tsconfig.json
{
 "compilerOptions": {
 "stableTypeOrdering": true
 }
}

Si votre travail consiste à maintenir des paquets open source ou à soumettre des fichiers de déclaration générés au contrôle de version, il est judicieux d’activer ce paramètre et de le tester dès aujourd’hui. Cela garantit que vos tests d’aperçu ainsi que les types générés ne produiront pas de différences sans signification lorsque vous passerez finalement à TypeScript 7.

Liste de contrôle pour une migration pratique

Passer à une nouvelle version d’un codebase important n’a pas besoin d’être difficile si vous l’abordez par étapes. Prenez en compte ces priorités :

Vérifiez d’abord chaque drapeau lié à strict, car c’est votre meilleure protection contre l’apparition de valeurs implicites any et de références null non sécurisées avant l’arrivée de la version 7 — priorité élevée. Supprimez les configurations de modules obsolètes, en abandonnant AMD, UMD ainsi que la stratégie traditionnelle de résolution des modules node — priorité élevée. Activez verbatimModuleSyntax afin que la génération de JavaScript ne dépende plus du tout du vérificateur de types — priorité moyenne. Adoptez les importations par sous-chemin en utilisant le préfixe #, ce qui élimine la nécessité d’astuces de résolution de chemins spécifiques au bundler — priorité moyenne. Définissez explicitement rootDir pour éviter toute surprise concernant la structure de votre dossier de sortie lorsque les builds sont exécutées en parallèle — priorité faible.

Erreurs courantes à éviter

Erreur 1 : Désactiver le mode strict pour corriger les erreurs de mise à niveau

Un réflexe courant après la mise à niveau vers TypeScript 6 et l’apparition d’une série de nouveaux erreurs est de simplement définir "strict": false afin que l’intégration continue fonctionne à nouveau.

Cette solution peut vous permettre de surmonter l’obstacle à court terme, mais elle ne fait que reporter le travail réel. Les améliorations de performance apportées par TypeScript 7 reposent sur l’hypothèse d’un typage fiable. Plutôt que de désactiver complètement le mode strict, désactivez temporairement des vérifications spécifiques — par exemple "noImplicitAny": false — et corrigez progressivement les erreurs qui en résultent, fichier par fichier.

Erreur 2 : Mélanger les importations de types et de valeurs

Une fois verbatimModuleSyntax activé, ne combinez pas les importations de types et de valeurs dans une seule instruction :

// À éviter
import { User, UserService } from "./userService";
// Préférer
import { UserService } from "./userService";
import type { User } from "./userService";

Les garder séparés évite toute ambiguïté — tant pour les lecteurs que pour le compilateur — quant à savoir quels imports servent uniquement au contrôle de type et lesquels contiennent du code exécuté réellement.

Le contexte global : Que se passe-t-il ensuite ?

TypeScript 6 ne cherche pas à vous imposer une multitude de nouvelles syntaxes à apprendre. Son véritable objectif est de stabiliser la situation avant un changement bien plus important.

En mettant à jour votre tsconfig.json dès maintenant, en passant à des importations explicites de type uniquement, et en éliminant le traitement des chemins de l’ancienne version, vous éliminez la majeure partie des difficultés auxquelles vous seriez confronté par la suite. Une fois TypeScript 7 disponible, la mise à niveau ne consistera guère qu’à augmenter la version du package et à exécuter le nouveau compilateur natif — avec des temps de compilation tombant bien en dessous d’une seconde, sans besoin de réécrire votre code existant.

Réservez un court moment cette semaine pour examiner la configuration de votre projet. Il s’agit d’un petit investissement qui rapportera des avantages considérables plus tard.

Quel est votre plan pour la mise à niveau ?

Votre équipe utilise-t-elle déjà le mode strict activé en totalité, ou êtes-vous encore en train de résoudre les anciennes options de configuration ? Avez-vous commencé à expérimenter avec les importations par sous-chemin dans vos propres projets ? Partagez vos idées et questions dans les commentaires.

Lectures complémentaires

  • Remplacer Jest par le moteur de tests natif de Node dans Node 24 — Une migration réelle montre comment le moteur de tests intégré à Node 24 ainsi que son support natif pour TypeScript réduisent le temps de CI tout en éliminant quatre dépendances.
  • Comparaison des agents IA Frontier : Astra, Flash, Fable et Mythos — Une analyse de la performance des dernières versions des modèles GPT, Gemini et Claude sur des tâches d’agent réelles telles que le codage, la navigation et l’utilisation d’outils, et non seulement sur des benchmarks.
  • La réécriture en Go de TypeScript 7 : quelles conséquences pour la sécurité des types dans React — Découvrez comment le compilateur basé sur Go de TypeScript 7 accélère les builds et améliore l’inférence générique, éliminant ainsi les types any cachés dans les hooks React et JSX.
  • Le compilateur en Go de TypeScript et l’exécution native : un guide de migration — Apprenez comment le compilateur basé sur Go de TypeScript et l’exécution native de Node.js affecteront les projets React et Next.js, ainsi que ce qu’il convient de corriger dans votre tsconfig dès maintenant.