TypeScript 7へ移行する前に押さえておくべき互換性の問題とCI最適化
29. Juli 2026
0
Computing/SoftwareRelated Video
8:32TypeScript 7が正式リリース、驚異的なスピードを実現
Better Stack
Comments (0)
Log in to leave a comment
No posts yet
8:32Better Stack
Log in to leave a comment
No posts yet
コンパイラをGoで再構築して作られたTypeScript 7がリリースされた。型チェック速度が最大12倍高速化したというニュースに、大規模なモノレポを運用するチームなら今すぐにでも移行したいと思うだろう。実際にVantaやVS Codeのエンジニアリングチームは、CIパイプラインのビルド時間を80%以上削減したと明かしている。
しかし、闇雲に適用するとCIが丸ごと壊れてしまう。ネイティブバイナリに切り替わったことで、従来の静的解析APIのサポートが後続バージョンへ見送られたためだ。@typescript-eslintやts-morphのように、require('typescript')で内部APIを参照していたツールが一斉に動作しなくなる。パフォーマンスは魅力的だが、ツールチェーンが破損するのは別の問題だ。デプロイの停止を防ぎつつ速度の恩恵だけを享受するには、いくつかの回避策が必要となる。
TypeScript 7.0のtscバイナリは、Node.jsの内部モジュール呼び出しを完全に遮断する。従来のようにJS環境からインポートして使用していたパッケージは、ビルド時に即座にエラーを吐くようになる。準備なしにバージョンだけを上げると、CIパイプライン全体が麻痺してしまう。
パイプラインの最上流に診断スクリプトを挟んでおくのが安全だ。ワークスペース内のすべてのpackage.jsonとtsconfig.jsonを走査し、TS 7で拒否されるオプションやパッケージを検出する手法である。ignoreDeprecationsやtarget: es5のような古い設定が残っている場合、即座にエラーを出力してプロセスを停止させる。
`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();
`
ts.createProgram()やts.transform()に依存するカスタムASTトランスフォーマも動作しない。TS 7.0は外部JSプラグインの注入を受け付けないためだ。こうしたロジックはSWCやBabelのようなRust/C++バインディングモジュールに置き換えるか、コンパイル工程の外に切り離す必要がある。
| コンパイラオプション | TypeScript 6.0の動作 | TypeScript 7.0の動作 | 対応方法 |
|---|---|---|---|
target |
es5使用時に警告 |
Hard Error (コンパイル中断) | es2022以上に変更 |
moduleResolution |
node設定を許容 |
Hard Error | bundlerまたはnode16に変更 |
baseUrl |
単独使用を許容 | Hard Error | compilerOptions.pathsの単독使用へ移行 |
ignoreDeprecations |
警告無視が動作 | オプション無効化およびエラー | 該当設定を完全に削除 |
strict |
デフォルト値 false |
デフォルト値 true |
tsconfig.json内で明示的な値を設定 |
TypeScript 7はGoのスレッディングモデルを活用している。型チェックを並列処理する--checkersと、プロジェクトリファレンスのビルドを制御する--buildersオプションが新しく提供された。Slackのエンジニアリングチームは、これらのオプションを組み合わせて型チェック時間を20分から4.5分へと短縮した。ただし、コア数に合わない過剰なスレッド数を設定すると、CPUのコンテキストスイッチングオーバーヘッドが大きくなり、OOM(Out of Memory)でビルドが落とされる。
ランナーのスペックに合わせて、以下の公式からスレッド数を算出するのが望ましい。仮想マシンの割当コア数を 、総メモリを 、OS予約メモリを ()、ワーカーあたりの平均メモリ占有量を ()とすると、単一プロジェクトにおける最適スレッド数 は次のようになる。
N_{checkers} = minleft( C_{vCPU}, leftlfloor rac{M_{total} - M_{OS}}{M_{worker}} ight floor ight)全スレッドの合計である が を超えないようにする必要がある。例えば 8 vCPU / 16GB のランナー環境であれば、--checkers 4、--builders 2 の設定が適切だ。
`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
`
注意すべき点がある。TS 7の増分コンパイルエンジンは、従来のTS 6の .tsbuildinfo キャッシュファイルとフォーマットが互換しない。ビルド前に find . -name "*.tsbuildinfo" -delete で旧バージョンのキャッシュを削除しておかないと、セグメンテーション違反が発生する。
エディタ向けの言語サーバーもGoバイナリベースのLSPへと刷新された。AWS CodeBuildでのテスト結果によると、大規模モノレポでファイルを開いてから最初の型エラーが表示されるまでの時間が17.5秒から1.3秒へと短縮された。
チームメンバーのVS Code環境を統一するには、モノレポ直下の .vscode/settings.json に以下の設定を追加するとよい。
`json
{
"typescript.tsdk": "node_modules/typescript/lib",
"js/ts.experimental.useTsgo": true,
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.preferences.preferTypeOnlyAutoImports": true,
"files.associations": {
"*.tsbuildinfo": "json"
}
}
`
VueやSvelteのようなテンプレート言語のプラグインと衝突し、構文解析がクラッシュするケースが稀に発生する。そのような場合は、コマンドパレット (Ctrl+Shift+P) から TypeScript: Select TypeScript Version... を選択し、従来のTS 6.0エンジンに戻して作業すれば回避できる。
プロジェクトにレガシーパッケージが絡み合っており、今すぐESLintをTS 7環境へ上げられない場合は、コンパイラを2つ併用するデュアルエンジン構成で回避できる。静的解析ツールにはTS 6のAPIを接続し、実際の型チェックとビルドのみをTS 7のネイティブバイナリに委ねる形だ。
package.json でパッケージエイリアス(Alias)を指定し、両方のコンパイラを同時にインストールする。
`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 ."
}
}
`
この状態でCIにシャドービルド(Shadow Build)スク립トを組み込んでおくと安全だ。従来のTS 6による診断結果とTS 7による診断結果を diff で比較し、テンプレートリテラル型や条件付き型の推論で結果に差が生じていないかをモニタリングできる。
`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
`
ツールチェーンの互換性問題が解消されるまでは、リントと型チェックの役割を分離して運用するのが現実的だ。事前診断スクリプトで破綻しそうなオプションを整理し、CIインフラのスペックに合わせてスレッド数を調整すれば、デプロイパイプラインを止めることなく速度向上の恩恵を享受できる。