TypeScript 7.0 RC 公開、Go によるネイティブ移植で約10倍高速に
TypeScript は、JavaScript に静的型付けを加えた言語です。コンパイラが型チェックを行い、エラーを早期に発見した上で、型注釈を除いた純粋な JavaScript に変換して出力します。大規模なフロントエンド開発では事実上の標準といえるほど広く使われ、Node.js などサーバーサイドでも採用が進んでいます。VS Code をはじめ多くのエディタと深く統合されています。
そのコンパイラが今回、完全に新しい土台の上で作り直されました。TypeScript 7.0 RC が公開され、内部実装を Go 言語へ移植した新エンジンが初めて RC として公開されています。インストールはこれだけです。
npm install -D typescript@rc
npx tsc --version
# Version 7.0.1-rc
7.0 の tsc は従来どおり使えます。オプションも出力も変わらず、ただ速い。その「なぜ速いのか」「何が変わったのか」を以下で詳しく見ていきます。
書き換えではなく「移植」
よくある誤解を最初に解きます。TypeScript 7.0 は「ゼロから Go で書き直した別物」ではありません。
TypeScript はもともと TypeScript 自体で書かれた self-hosted なコンパイラです。それを過去1年かけて Go へ「方法論的に移植(methodically ported)」しました。型チェックのロジックは 6.0 と**構造的に同一(structurally identical)**で、同じセマンティクスを保証します。
この点は採用判断において非常に重要です。「速くなる」こと自体より、結果が変わらない忠実な移植であるという担保があってこそ、既存のコードベースに安心して導入できます。新言語への書き換えが孕む「微妙な挙動の違い」を心配しなくて済む設計になっています。
検証も徹底されています。10年かけて蓄積した巨大なテストスイートで動作を確認済みで、Microsoft 内外の数百万行規模のコードベースでは既に使用中。Bloomberg、Canva、Figma、Google、Notion、Slack、Vercel などが pre-release を試用し、ビルド時間の大幅な短縮を報告しています。
リポジトリは microsoft/typescript-go(Go 言語、Apache-2.0)で公開されています。
なぜ約10倍速いのか
速度向上の要因は大きく2つあります。ネイティブコードで動作することと、並列処理です。
従来の TypeScript コンパイラは Node.js 上の JavaScript として動いていました。Go にネイティブコンパイルされた 7.0 は JIT ウォームアップなしで即座に動き始め、共有メモリを使った並列処理が可能になります。
TypeScript 7.0 は parsing・type-checking・emitting を並列実行します。parse と emit はファイル間でほぼ独立して行えるため、ファイル数が増えるほどスケールします。大規模なモノレポほど恩恵が大きい設計です。
並列化の制御フラグ
並列度を細かく調整するフラグが3つあります。
--checkers
型チェックワーカーの数を指定します(デフォルト: 4)。型チェックはファイル間の依存が複雑なため、固定数のワーカーが独自の世界観を持ちながら並列処理する方式を採っています。同じ入力なら必ず同じ分割・同じ結果が出ることが保証されています。
npx tsc --checkers 8 # コア数が多いマシンで増やす(メモリも増える)
npx tsc --checkers 2 # CI ランナー等リソースが限られる環境では減らす
まれに checkers 数を変えると順序依存の結果が出ることがあるため、環境間で値を固定すると再現性が高まります。CI のベースライン比較を CI 環境と同じ checkers 数で取る、という運用が安定します。
--builders
プロジェクト参照(project references)を並列ビルドするビルダー数です。モノレポで複数パッケージを一度にビルドするとき有効で、checkers と乗算的に効きます。
npx tsc --checkers 4 --builders 4
# 最大で 16 の型チェッカーが同時起動し得る
# 小さなプロジェクトでは過剰になりうるので注意
builders の数を変えても型チェックの結果は変わりません。
--singleThreaded
型チェッカーを1に制限し、parse・emit も単一スレッドで動かします。利用シーンはいくつかあります。
- 6.0 との性能比較をフェアに取りたいとき
- 問題の切り分けやデバッグ時
- 外部のビルドシステムが並列化を管理していて TypeScript 側では絞りたいとき
- CI ランナーなどリソースが厳しく制限された環境
再構築された --watch
7.0 の --watch は、Parcel バンドラの file-watcher ライブラリを土台にした新基盤で、効率的で安定したクロスプラットフォーム監視を提供します。
Go には標準の file watching API がなく、サードパーティも安定性・性能・クロスプラットフォーム対応に難がありました。ポーリング方式は動作するものの、node_modules を多く含む大規模プロジェクトでは計算コストが高すぎます。
VS Code が長年 @parcel/watcher を使ってきた実績があります。ただし Parcel の watcher はC++製でビルドにフルのC++ツールチェーンが必要です。そこで最小限のアセンブリ shim を使ってGoへ移植し、新たなツールチェーン依存を避けました。C++からの直訳をイディオマティックなGoに洗練させ、移植したテストスイートも通過しています。Parcel 作者の Devon Govett 氏への謝辞も公式ブログに記されています。
6.0 とのサイドバイサイド運用
7.0 RC は本番に近い完成度ですが、安定した programmatic API の提供は早くても数ヶ月後の TypeScript 7.1 まで予定されていません。そのため当面は 6.0 と衝突なく並走できる仕組みが整えられています。
公式が推奨する構成は、typescript という名前を 6.0 に固定したまま 7.0 を別名で追加する形です。typescript-eslint など一部のツールが typescript を peer dependency として直接 import するため、typescript という名前は 6.0 に保っておく必要があります。
{
"devDependencies": {
"typescript": "npm:@typescript/typescript6@^6.0.0",
"typescript-7": "npm:typescript@rc"
}
}
この構成では、7.0 パッケージが自前の tsc バイナリを同梱するため npx tsc は 7.0 として動きます。6.0 の tsc は tsc6 として引き続き使えます。import ... from "typescript" は 6.0 を指すため、typescript-eslint などのツール互換も保たれます。
なお @typescript/typescript6 は、tsc6 という実行ファイルを提供し、6.0 の API を re-export する互換パッケージです。
なお、nightly 版は現状 @typescript/native-preview パッケージ(バイナリ名は tsgo)で配信されています。
npm install -D @typescript/native-preview
npx tsgo --version
将来 7.0 が latest タグで出れば、安定版・nightly とも typescript パッケージに集約される予定です。
7.0 で「硬いエラー」になる移行ポイント
7.0 は 6.0 の型チェック・CLI 挙動と互換になるよう設計されています。6.0 で stableTypeOrdering オン・ignoreDeprecations なしでクリーンにコンパイルできるコードは、7.0 でも同一にコンパイルできるはずです。
ただし、7.0 は 6.0 の新デフォルトを採用し、6.0 で非推奨だったフラグ・構文に対して硬いエラー(hard error)を出します。6.0 がまだ比較的新しいため、多くのプロジェクトは何らかの対応が必要になります。先に 6.0 へ上げて非推奨を潰してから 7.0 に移行すると痛みが少なくなります。
デフォルト値の変更
以下の設定が 7.0 の新デフォルトです。tsconfig.json に明示していない場合はこれらが適用されます。
strict: 既定truemodule: 既定esnexttarget:esnextの一つ前の安定 ECMAScript バージョンnoUncheckedSideEffectImports: 既定truelibReplacement: 既定falsestableTypeOrdering: 既定trueで無効化不可rootDir: 既定./(src/配下だけをコンパイルしている場合は明示が必要)types: 既定[](旧挙動は["*"])
rootDir と types が最も驚かれやすい変更です。ただし対処は難しくありません。
// 7.0 に対応した tsconfig.json の差分例
{
"compilerOptions": {
// tsconfig が src/ の外にある場合は rootDir を明示
"rootDir": "./src",
// グローバル型に依存しているなら types を明示
// (旧デフォルト ["*"] から空配列になるため)
"types": ["node", "jest"],
// target・module を明示して意図を固定する
"target": "es2022",
"module": "esnext"
}
}
廃止フラグ → 硬いエラー
6.0 で非推奨だった以下の設定が、7.0 ではコンパイルエラーになります。
target: "es5"廃止downlevelIteration廃止moduleResolution: "node"/"node10"廃止 →"nodenext"または"bundler"を推奨module: "amd"/"umd"/"systemjs"/"none"廃止 →"esnext"または"preserve"を推奨baseUrl廃止(pathsはプロジェクトルート相対で記述する)moduleResolution: "classic"廃止esModuleInterop: falseおよびallowSyntheticDefaultImports: falseは不可alwaysStrictはtrue固定(false不可)
target: "es5" の廃止は特に影響範囲が広く、IE11 対応を維持していたレガシーなコードベースでは移行の検討が必要です。ダウンレベルトランスパイルは Babel や esbuild など専用ツールに任せる方向が現実的でしょう。
エディタ体験
性能改善は CLI だけにとどまりません。VS Code 向けに「TypeScript Native Preview」拡張が公開されており、インストールするだけで 7.0 エンジンによる補完・型チェックが有効になります。Visual Studio は最新版がワークスペースに応じて自動的に 7 を有効化します。
新基盤は Language Server Protocol(LSP)上に構築されており、複数スレッドで同時リクエストを捌きます。公式データでは、失敗する language server コマンドが 6.0 比で20倍以上削減されたとのことです。Copilot CLI のようなツールからも動かしやすい設計になっています。
実際の移行でどう動くか
7.0 安定版は今後1ヶ月程度での公開が計画されています。フィードバックは microsoft/typescript-go の issue tracker で受け付けています。
移行の進め方として、次の順序をおすすめします。
- まず 6.0 へ上げる。
ignoreDeprecationsなしでクリーンにコンパイルできる状態にしておく。この段階で廃止フラグを整理しておくと、7.0 移行時のエラーがほぼなくなります。 - サイドバイサイドで 7.0 RC を試す。前述のエイリアス方式で 7.0 の
tscを別名で導入し、CI に追加ジョブとして流してみます。 - CI の
--checkersを固定する。デフォルトの 4 のままでも多くの場合は問題ありませんが、環境間でバラつかないよう明示しておくと安心です。
# CI での例:checkers を明示して再現性を担保
npx tsc --noEmit --checkers 4
「速くなる」というメリットは明快ですが、実際の採用判断を軽くしているのは忠実な移植という設計です。型チェックの結果が変わらないという保証があるからこそ、既存の CI パイプラインをほぼそのままに移行できます。まずは 6.0 で非推奨を潰して土台を整えてから、7.0 に踏み出すのが最もストレスの少ない道筋です。