TypeScriptのコンパイラがGoで書き直されて10倍速くなった!何が変わった?なぜGo?
tscが遅いと思ったことはないか
TypeScriptで開発していると、tsc --noEmit や tsc -b の待ち時間が地味に長い。CIで型チェックが走るたびに数十秒〜数分待たされる。プロジェクトが大きくなるほど、じわじわ効いてくる。
2026年1月、TypeScript 7.0 がリリースされた。
何が変わったか。コンパイラがGo言語でネイティブに書き直された。プロジェクト名は「Project Corsa」。新しいコマンドは tsgo。
結果、コンパイル速度が約10倍になった。
……10倍?
しかも、書き直し先がGoだという。Rustでもなく、C#でもなく、Go。TypeScriptの生みの親であるAnders HejlsbergはC#も作った人なのに、自分の言語を選ばなかった。
なんでGoなのか気になったので、調べてみた。
どれくらい速くなったのか
まず、「10倍」が本当かどうか。公式ブログと各種ベンチマークから数字を見てみる。
大規模プロジェクトでのコンパイル速度
| プロジェクト | コード量 | tsc 6.0 | tsgo 7.0 | 倍率 |
|---|---|---|---|---|
| Sentry | - | 133.08s | 16.25s | 8.2x |
| VS Code | ~150万行 | 89.11s | 8.74s | 10.2x |
| TypeORM | - | 15.80s | 1.06s | 9.9x |
| Playwright | 35.6万行 | 9.30s | 1.24s | 7.5x |
出典: A 10x Faster TypeScript - TypeScript Blog
VS Codeの150万行のコードベースが、89秒から8.7秒になっている。桁が変わっている。
エディタの起動速度
エディタの言語サービス(補完やGo-to-Definitionなど)の起動時間も大幅に改善している。
- VS Codeコードベースで 9.6秒 → 1.2秒(約8倍)
- メモリ使用量は約 50%削減
出典: A 10x Faster TypeScript - TypeScript Blog
大規模プロジェクトを開いた瞬間からサクサク動く、というのは体験として大きい。
小規模プロジェクトでも効果あり
「大規模だから効くだけでしょ?」と思うかもしれないが、700行程度のバックエンドコードでも検証されている。
| 指標 | tsc | tsgo | 改善 |
|---|---|---|---|
| トータル時間 | 0.28s | 0.026s | 10.8x |
| 型チェック | 0.10s | 0.003s | 33.3x |
| メモリ使用量 | 68,645K | 23,733K | 2.9x 削減 |
出典: tsgo Released! Installation Guide & 10x Speedup Verification - DEV Community
小さいプロジェクトでも10倍速い。型チェック単体だと33倍。「10倍」は誇張ではなかった。
そもそも、なぜ遅かったのか
速くなった理由を理解するには、まず「なぜ遅かったのか」を知る必要がある。
TypeScriptのコンパイラ(tsc)は、TypeScript自身で書かれていた。いわゆるセルフホスティングコンパイラだ。
TypeScriptで書かれたコンパイラはJavaScriptにコンパイルされ、Node.js上で実行されていた。つまり:
- インタプリタ + JIT コンパイルのオーバーヘッド: コンパイラのような計算量の多い処理に対して、ネイティブコードほど効率的ではない
- シングルスレッド: Node.jsはシングルスレッドなので、マルチコアCPUを活かせない
- GCの最適化限界: V8のGCは汎用的で優秀だが、コンパイラのような特殊なメモリアクセスパターンに最適化されているわけではない
この構造が、プロジェクト規模に比例してボトルネックになっていた。
なぜGoなのか
ここが一番気になったところだ。
「ネイティブに書き直して速くなった」のはわかる。でも、なぜGoなのか。速さだけで言えばRustの方が速い。GCがない分、オーバーヘッドが小さいからだ。C#はHejlsberg自身が作った言語だ。Javaはエンタープライズの実績が豊富だ。
TypeScriptチームの答えは明確だった。
大前提:これは「書き直し」ではなく「移植」
ここが一番大事なポイントだ。
チームがやりたかったのは、既存のTypeScriptコンパイラのコードをできるだけそのまま別言語に変換することだった。ゼロから設計し直すのではなく、既存の動作・互換性を維持したまま速くしたかった。
つまり、言語選びの最重要基準は 「最速であること」ではなく「移植しやすいこと」 だった。
この前提を踏まえると、Goが選ばれた理由が見えてくる。
理由1:GC(ガベージコレクション)が必要だった
TypeScriptコンパイラは、循環参照を多用した複雑なデータ構造に依存している。AST(抽象構文木)、型情報、シンボルテーブルなどが互いに参照し合う構造だ。
GoにはGCがある。循環参照があっても問題なく回収できる。
RustにはGCがない。Rustの所有権モデルでは、循環参照を含むデータ構造を扱うにはRc<RefCell<T>>のようなパターンを使うか、根本的にデータ構造を再設計する必要がある。つまり、「移植」ではなく「完全な書き直し」になってしまう。
理由2:コード構造がほぼ1:1で対応していた
TypeScriptのコンパイラは、クラスベースのOOPではなく関数 + データ構造中心の設計になっている。
Goのイディオムはstruct + 関数だ。この構造がTypeScriptのコンパイラのコードとほぼ1:1で対応していた。
Hejlsberg自身が「plug and play replacement(差し替えるだけ)」と表現している。既存のコードを機械的に変換できるレベルで構造が合致していたということだ。
一方、C#やJavaはクラスベースの言語だ。関数+データ構造中心の設計を移植するには、無理やりクラスに押し込めるか、構造を変える必要がある。Hejlsberg自身がC#を評価した上で却下している。
理由3:ネイティブバイナリの配布が容易
go build で各OS向けの単体バイナリを生成できる。追加のランタイムは不要だ。
npmパッケージにバイナリを同梱すれば、ユーザーは npm install するだけで使える。TypeScript開発者が普段使っているワークフローをそのまま維持できる。
C#でもネイティブバイナリは生成できるが、クロスプラットフォームでの配布はGoほど容易ではない。
理由4:並行処理で遅さの根本原因を解消
GoにはGoroutineがあり、shared-memory parallelismが得意だ。
これにより、旧tscがNode.jsのシングルスレッドで動いていた制約を根本的に解消できた。シングルプロジェクトのマルチスレッドビルドと、並列マルチプロジェクトビルドの両方を実現している。
Hejlsbergの言葉
"JavaScript was never really intended to be the language for compute-intensive, system-level workloads. Go was precisely intended to be that… Go is a system-level tool, and we are a systems-level program."
TypeScriptのdev leadであるRyan Cavanaughも、選択の現実を端的に語っている。
"In the end we had two options — do a complete from-scratch rewrite in Rust, which could take years and yield an incompatible version of TypeScript that no one could actually use, or just do a port in Go and get something usable in a year or so."
各言語が落ちた理由まとめ
| 言語 | 落ちた理由 | 情報源 |
|---|---|---|
| Rust | GCなし → 循環参照だらけのデータ構造を根本から再設計 → 完全な書き直しに何年もかかる | 公式発言 |
| C# | クラスベース → 関数+データ構造中心のtscと構造が合わない。Hejlsberg自身が評価して却下 | 公式発言 |
| Java | JVMが必要 → 配布時にJDK依存。クラスベースで構造も合わない | ⚠️ 推測※ |
| Go | GCあり、関数+構造体で移植しやすい、ネイティブバイナリ、goroutine → 全条件に合致 | 公式発言 |
※ Javaについては、チームの公式Discussion(#411)やブログ記事で明確な候補として議論された形跡がない。上記の理由はGoの選定基準から逆算した推測。
TypeScript 7で変わること
速くなるだけではない。いくつかの破壊的変更がある。
-
--target es5が廃止(最低がes2015) -
--strictがデフォルトで有効に -
--moduleResolution node10が廃止(デフォルトはbundler) --baseUrlが廃止
TypeScript 6.0が最後のJSベースリリースで、ts5to6 ツールでtsconfig.jsonの自動アップデートもできる。90%のプロジェクトは2時間以内に移行できるとのこと。
今すぐ試したい場合:
npm install -D @typescript/native-preview
npx tsgo -p .
まとめ
- TypeScript 7.0のコンパイラはGoで書き直され、約10倍速くなった
- 「10倍」は大規模プロジェクトでも小規模プロジェクトでも再現される実測値
- Rustの方が理論上速いが、TypeScriptチームが重視したのは**「移植しやすさ」**だった
- GC、コード構造の互換性、バイナリ配布、並行処理 — すべての条件を満たしたのがGoだった
個人的に一番印象的だったのは、「最速」ではなく「実用性」を選んだという判断だ。
Rustで書き直せば理論上もっと速くなったかもしれない。でもそれには何年もかかり、互換性が壊れるリスクがあった。Goで移植すれば1年程度で、互換性を保ったまま10倍速くできた。
技術選定は「何ができるか」だけじゃなく、「どれだけ早く、確実に届けられるか」も大事だという好例だと思う。
Discussion