Problèmes de compatibilité et optimisation du CI avant de passer à TypeScript 7
٢٩ يوليو ٢٠٢٦
0
Computing/SoftwareComments (0)
Log in to leave a comment
No posts yet
Log in to leave a comment
No posts yet
TypeScript 7 est arrivé, entièrement réécrit en Go. Avec l'annonce d'une vérification de type jusqu'à 12 fois plus rapide, les équipes gérant de grands monorepos voudront certainement l'adopter immédiatement. En fait, les équipes d'ingénierie de Vanta ou de VS Code ont déclaré avoir réduit le temps de build de leur pipeline CI de plus de 80 %.
Cependant, une adoption aveugle risque de faire planter tout votre CI. Le passage à un binaire natif a repoussé le support des API d'analyse statique existantes aux versions ultérieures. Les outils qui inspectaient les API internes via require('typescript'), comme @typescript-eslint ou ts-morph, se retrouvent tous hors service. Si les performances sont séduisantes, le bris de la chaîne d'outils est un tout autre problème. Pour profiter du gain de vitesse tout en évitant l'interruption des déploiements, quelques contournements sont nécessaires.
Le binaire tsc de TypeScript 7.0 bloque complètement l'appel aux modules internes de Node.js. Les paquets qui étaient importés et utilisés dans l'environnement JS comme auparavant génèrent immédiatement des erreurs au moment du build. Une simple montée de version sans préparation peut paralyser l'ensemble du pipeline CI.
Il est plus sûr de placer un script de diagnostic tout en haut du pipeline. Cette méthode consiste à parcourir tous les package.json et tsconfig.json du workspace pour identifier les options ou paquets rejetés par TS 7. Si des configurations obsolètes comme ignoreDeprecations ou target: es5 subsistent, le script émet immédiatement une erreur et stoppe le processus.
`javascript
// scripts/check-ts7-compatibility.mjs
import fs from 'node:fs';
import { globSync } from 'glob';
const INCOMPATIBLE_DEPS = [
'ts-morph',
'ts-node',
'@babel/plugin-transform-typescript',
'typescript-eslint',
'@typescript-eslint/parser'
];
const DEPRECATED_TSCONFIG_OPTIONS = ['target:es5', 'moduleResolution:node', 'baseUrl', 'ignoreDeprecations'];
function runDiagnostics() {
console.log('TypeScript 7 호환성 사전 진단 시작...');
let hasError = false;
const packageFiles = globSync('/package.json', { ignore: '/node_modules/' });
for (const file of packageFiles) {
const content = JSON.parse(fs.readFileSync(file, 'utf8'));
const allDeps = { ...content.dependencies, ...content.devDependencies };
for (const dep of INCOMPATIBLE_DEPS) {
if (allDeps[dep]) {
console.warn([의존성 경고] ${file}: '${dep}' 패키지는 TS7 네이티브 API와 호환되지 않습니다.);
hasError = true;
}
}
}
const tsconfigFiles = globSync('/tsconfig*.json', { ignore: '/node_modules/' });
for (const file of tsconfigFiles) {
const rawContent = fs.readFileSync(file, 'utf8');
for (const opt of DEPRECATED_TSCONFIG_OPTIONS) {
if (rawContent.includes(opt)) {
console.error([설정 오류] ${file}: 무효화된 옵션 발견 -> '${opt}');
hasError = true;
}
}
}
if (hasError) process.exit(1);
}
runDiagnostics();
`
Les transformateurs AST personnalisés reposant sur ts.createProgram() ou ts.transform() ne fonctionnent pas non plus. TS 7.0 n'accepte pas l'injection de plugins JS externes. Cette logique doit être remplacée par des modules de liaison Rust/C++ comme SWC ou Babel, ou être extraite de la phase de compilation.
| Option du compilateur | Comportement TypeScript 6.0 | Comportement TypeScript 7.0 | Solution |
|---|---|---|---|
target |
Avertissement lors de l'utilisation de es5 |
Hard Error (Interruption de la compilation) | Passer à es2022 ou supérieur |
moduleResolution |
Autorise la configuration node |
Hard Error | Passer à bundler ou node16 |
baseUrl |
Autorise une utilisation isolée | Hard Error | Passer à l'utilisation isolée de compilerOptions.paths |
ignoreDeprecations |
L'ignorance des avertissements fonctionne | Option invalidée et erreur | Supprimer complètement ce paramètre |
strict |
Valeur par défaut false |
Valeur par défaut true |
Définir une valeur explicite dans tsconfig.json |
TypeScript 7 exploite le modèle de threading de Go. Il propose de nouvelles options : --checkers pour traiter la vérification de type en parallèle et --builders pour contrôler le build des références de projet. L'équipe d'ingénierie de Slack a combiné ces options pour réduire le temps de vérification de type de 20 minutes à 4,5 minutes. Néanmoins, si le nombre de threads est surévalué par rapport au nombre de cœurs, le surcoût lié au changement de contexte CPU augmente et le build plante en raison d'un OOM (Out of Memory).
Il vaut mieux fixer les threads selon la formule suivante, adaptée aux spécifications du runner. Si l'on note le nombre de cœurs alloués à la machine virtuelle , la mémoire totale , la mémoire réservée à l'OS (), et l'occupation mémoire moyenne par worker (), le nombre optimal de threads pour un seul projet s'obtient ainsi :
N_{checkers} = minleft( C_{vCPU}, leftlfloor rac{M_{total} - M_{OS}}{M_{worker}} ight floor ight)La somme totale des threads ne doit pas dépasser . Par exemple, dans un environnement de runner à 8 vCPU / 16 Go, la configuration --checkers 4 et --builders 2 est appropriée.
`yaml
name: Monorepo Parallel Typecheck
on:
push:
branches: [main]
jobs:
typecheck:
runs-on: ubuntu-latest-8-core
steps:
- name: Checkout Codebase
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Purge Legacy TS 6.0 Cache
run: find . -name "*.tsbuildinfo" -not -path "*/node_modules/*" -delete
- name: Execute TS 7 Parallel Check
run: npx tsc --build --checkers 4 --builders 2 --verbose
`
Un point requiert une attention particulière. Le moteur de compilation incrémentale de TS 7 présente un format incompatible avec les fichiers de cache .tsbuildinfo du précédent TS 6. Si vous ne supprimez pas le cache de l'ancienne version avec find . -name "*.tsbuildinfo" -delete avant le build, une erreur de segmentation surviendra.
Le serveur de langage pour l'éditeur a lui aussi été repensé sur la base d'un LSP en binaire Go. Selon les résultats des tests AWS CodeBuild, le temps nécessaire pour afficher la première erreur de type lors de l'ouverture d'un fichier dans un grand monorepo a été réduit de 17,5 secondes à 1,3 seconde.
Pour harmoniser l'environnement VS Code des membres de l'équipe, il suffit d'insérer les paramètres suivants dans le fichier .vscode/settings.json à la racine du monorepo :
`json
{
"typescript.tsdk": "node_modules/typescript/lib",
"js/ts.experimental.useTsgo": true,
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.preferences.preferTypeOnlyAutoImports": true,
"files.associations": {
"*.tsbuildinfo": "json"
}
}
`
Il arrive parfois que des conflits surviennent avec des plugins de langages de templates comme Vue ou Svelte, provoquant un arrêt de l'analyse syntaxique. Dans ce cas, il suffit d'ouvrir la palette de commandes (Ctrl+Shift+P), de cliquer sur TypeScript: Select TypeScript Version... et de basculer à nouveau vers l'ancien moteur TS 6.0 pour poursuivre le travail.
Si des paquets hérités sont enchevêtrés dans le projet et vous empêchent de faire passer ESLint immédiatement dans l'environnement TS 7, vous pouvez contourner le problème grâce à une configuration dual-engine qui utilise deux compilateurs en parallèle. L'idée consiste à connecter l'API TS 6 aux outils d'analyse statique, tout en confiant la vérification de type réelle et le build au seul binaire natif TS 7.
Dans le package.json, définissez des alias de paquets pour installer les deux compilateurs simultanément :
`json
{
"name": "monorepo-root",
"private": true,
"devDependencies": {
"typescript": "npm:@typescript/typescript6@^6.0.2",
"@typescript/native": "npm:typescript@^7.0.2",
"eslint": "^9.0.0",
"typescript-eslint": "^8.0.0"
},
"scripts": {
"typecheck": "ts-native --build",
"typecheck:legacy": "tsc6 --noEmit",
"lint": "eslint ."
}
}
`
Dans cet état, il est prudent d'attacher un script de build fantôme (Shadow Build) au CI. En comparant les résultats de diagnostic de l'ancien TS 6 et ceux de TS 7 à l'aide de diff, vous pouvez vérifier si les résultats divergent au niveau des types de littéraux de modèles ou de l'inférence de types conditionnels.
`bash
#!/usr/bin/env bash
set -e
echo "=== 1. 기존 TS 6.0 컴파일러 진단 출력 생성 ==="
npx tsc6 --noEmit --pretty false > ./ts6-baseline.log 2>&1 || true
echo "=== 2. 신규 TS 7.0 네이티브 컴파일러 진단 출력 생성 ==="
npx --package @typescript/native tsc --noEmit --pretty false > ./ts7-output.log 2>&1 || true
echo "=== 3. 진단 결과 Diff 대조 검증 ==="
DIFF_RESULT=$(diff ./ts6-baseline.log ./ts7-output.log || true)
if [ -z "DIFF_RESULT"
exit 0
fi
`
En attendant que les problèmes de compatibilité de la chaîne d'outils soient réglés, il est plus réaliste de séparer les rôles de linter et de vérificateur de type. En nettoyant les options à risque à l'aide d'un script de pré-diagnostic et en ajustant le nombre de threads aux spécifications de votre infrastructure CI, vous bénéficierez des gains de vitesse sans risquer de bloquer votre pipeline de déploiement.