Skip to content
Published on

TypeScript 7 が GA になった — 8~12倍は本物だが、今日移行できない人たちがいる

シェア
Authors

はじめに — 7月8日、tsgoはただのtscになった

2026年7月8日、TypeScript 7.0がGAになりました。1年以上プレビューとして動いていたGoネイティブポートが正式リリースに入りました。

この1年、このプロジェクトを追ってきた人ならtsgoという名前になじみがあるはずです。専用パッケージ(@typescript/native-preview)から専用バイナリとしてナイトリーが出ており、既存のtscと並べて動かすのが標準の手順でした。GAでその構図は消えました。 公式発表文にはtsgoという語が一度も出てきません。代わりにこう書かれています — npm install -D typescriptをすれば「新しいtsc実行ファイル」が入る、と。

つまりネイティブポートはオプトインではなくデフォルトです。npmレジストリを直接確認すると、typescriptlatestタグは7.0.2で、公開日は2026年7月8日 — 発表文のGA日と正確に一致します。そして@typescript/native-previewの最後の公開は7月7日、GAの一日前で止まっています。ナイトリーは今typescript@nextに移りました(現在7.1.0-dev系列)。

リリースタイムラインはこう進みました — ベータ4月21日、RC 6月18日、GA 7月8日。

この記事は「Goポートは速い」を改めて説明する記事ではありません。それはTypeScript 6とtsc-goポートの回でプレビュー時代の基準としてすでに扱っており、正直に言えば当時想定していた配布形態(tsc --goのようなバックエンドフラグ、一つのメジャーバージョンが二つのコンパイラを一緒に出荷する形)と実際のGAは違います。実際にはメジャーバージョン自体が分かれました — 6はJS実装、7はGo実装です。この記事はGAで確定した事実だけを踏まえ、見出しの数字が隠す実際の移行コストを見ます。

数字を正確に — 何を測ったのか

発表文の表現は"10x faster native port"で、本文の条件付き文はこうです — ネイティブコードの速度、共有メモリのマルチスレッド化、複数の最適化がフルビルド(full builds)で通常8倍から12倍の速度向上をもたらす。

Microsoftが直接測定して公開したフルビルドの所要時間表です。これはベンダー自己報告の数値で、同じマシンでTypeScript 7のデフォルト設定で測ったものです。

コードベース    TS 6       TS 7       速度向上
vscode         125.7s     10.6s      11.9x
sentry         139.8s     15.7s       8.9x
bluesky         24.3s      2.8s       8.7x
playwright      12.8s      1.47s      8.7x
tldraw          11.2s      1.46s      7.7x

注目すべき点が二つ。第一に、表の下限は7.7倍で、「8~12倍」という自己申告よりわずかに低いです。第二に、速度向上はコードベースごとに異なります — vscodeの11.9倍とtldrawの7.7倍は1.5倍の差があります。大きいコードベースほど並列化の利得が大きくなる傾向が見られます。

メモリも同時に公開されていますが、ここはむしろ期待を下げるべき部分です。

コードベース    TS 6      TS 7      変化
vscode         5.2GB     4.2GB     -18%
sentry         4.9GB     4.6GB      -6%
bluesky        1.8GB     1.3GB     -26%
playwright     1.0GB     0.9GB     -11%
tldraw         0.6GB     0.5GB     -15%

プレビュー時代に語られていた「メモリ半減」という話とは違います。実際のGA数値は6%から26%の削減で、sentryはほぼ横ばいです。速度が一桁の倍率で跳ねたのに比べると、メモリは緩やかな改善です。発表文自身も「通常、フルビルド全体でより少ない総メモリを必要とする」という程度にしか述べておらず、それ以上は主張していません。

エディタ側の数字もあります。VS Codeのコードベースでエラーのあるファイルを開いたとき、最初のエラーが表示されるまで、同じマシンで以前は約17.5秒かかっていましたが、TypeScript 7では1.3秒未満 — 13倍以上速いということです。

企業事例として報告された数値は、もう一段慎重に読む必要があります。これはMicrosoftが各チームから伝え聞いたと明記している値です。

  • Slack — CI型チェック時間が約7.5分から1.25分に。マージキュー時間の40%が消えたとのこと。以前はエディタの言語サーバー読み込み時間のせいでローカル開発がほぼ「使い物にならない」水準で、エンジニアが全体の型チェックをCIに任せていましたが、今では同じコードベースが数秒で読み込まれるといいます。
  • Canva — エディタで最初のエラーが見えるまで約58秒から約4.8秒に。
  • Vanta — 最大のプロジェクト一つで最大9倍。
  • Microsoft News Servicesチーム — CIビルド待ちに使っていた時間を月400時間節約。

そして安定性の数値。Microsoftは自社のデータインサイトに基づき、7.0の新しい言語サーバーが6.0比で失敗する言語サーバーコマンドを80%以上、サーバークラッシュを60%以上削減したと述べています。これはテレメトリベースの自己測定であり、外部で再現できる種類の数字ではありません。

「10倍」にはダイヤルがある — --checkers

ここがGAで新たに明らかになった、そしてほとんどのまとめ記事が見落としている部分です。あのベンチマークの数字は特定の並列化設定の結果です。

TypeScript 7.0はパース、型チェック、エミットを並列に実行します。パースとエミットはファイル単位でほぼ独立しているため並列化がよく効きます。問題は型チェックです — ファイル間の依存が複雑で、大半のファイルが同じグローバルスコープと依存先の型情報に依存します。さらに型チェックは時にプログラム内の情報の相対的な順序に依存するため、結果を一定に保つには常に同じ順序でチェックする必要があります。

そこでTypeScript 7は固定数の型チェッカーワーカーを作ります。各ワーカーが自分だけの世界観を持ち、共通作業の一部を重複して行いますが、同じ入力であれば常に同じようにファイルを分割し、同じ結果を出します。

デフォルトのワーカー数は4です。先の表はすべてデフォルトの--checkers 4で測ったもので、発表文は同じマシンで--checkers 8で測り直した表を並べて掲載しています。

コードベース    TS 6       TS 7 (--checkers 8)    速度向上
vscode         125.7s     7.51s                  16.7x
sentry         139.8s    12.08s                  11.6x
bluesky         24.3s     2.01s                  12.1x
playwright      12.8s     1.16s                  11x
tldraw          11.2s     1.06s                  10.6x

チェッカーを8に上げるとvscodeは16.7倍まで伸びます。ただしこれはタダではありません — 発表文の表現どおりチェッカーを増やすと通常メモリ使用量の増加という代償が伴います。そして結果はプロジェクトとマシンによって変わります。

方向は逆にも働きます。CPUコアとメモリが少ない環境 — 発表文が直接例に挙げているのがCIランナーです — では、むしろこの値を下げて不要なオーバーヘッドを避けるほうがよい場合があります。--checkers 1まで指定でき、そうすると型チェックが事実上シングルスレッドになり重複作業が消えます。

ここで実務上もっとも重要な一文が出てきます。

稀なケースですが、--checkersの数を変えると順序依存の結果が現れることがあります。

つまりチェッカー数が診断結果に影響しうることを、チーム自身が認めているということです。発表文の推奨は、ビルド環境全体で固定のチェッカー数を指定して全員が同じ結果を得られるようにすることですが、それはチームの裁量だとも付け加えています。ローカルは8、CIは2、というようにばらばらにしておくと、「自分のマシンでは通るのにCIではエラー」が原理的に起こりうる余地が開くということです。私ならtsconfig.jsonであれCIスクリプトであれ、一か所に固定します。

関連するフラグがあと二つあります。--builders--buildモードで同時に動かすプロジェクト参照ビルダー数を調整します(モノレポ用)。注意すべきは--checkers掛け算で作用するという点です — 発表文の例のとおり、--checkers 4 --builders 4は最大16個の型チェッカーが同時に動くことを許し、これは過剰になり得ます。--singleThreadedは並列化を完全に切ります(デバッグ、6と7の性能比較、外部で並列ビルドを調整する場合、資源が非常に限られた環境向け)。--checkers--buildersは現在実験的(experimental)フラグとして紹介されています。

--builders--checkersと違い、数を変えても結果が変わらないことが明記されています。代わりにプロジェクト参照ビルドは根本的にプロジェクト依存グラフによってボトルネックが生じます。

本当のコスト(1) — 6の廃止予告がすべてハードエラーになった

ここからが支払いの部分です。

互換性そのものは良好です。発表文の条件付き文はこうです — stableTypeOrderingフラグをオンにしignoreDeprecationsフラグを設定していない状態でTypeScript 6.0でクリーンにコンパイルできるコードは、事実上何であれ7.0でも同じようにコンパイルできるはずだ。

問題はその前提です。7.0は6.0の新しいデフォルトをそのまま採用し、6.0で廃止予告されたフラグや構文に対してハードエラーを出します。発表文自身が認めるとおり「6.0は相対的にまだ新しく、多くのプロジェクトがその新しい挙動に適応する必要がある」状態です。だから公式の推奨は7へ直接飛ばず、6.0をまず導入して移行を楽にすることです。

まずデフォルト値の変更から見てみましょう。

strict                        -> デフォルトtrue
module                        -> デフォルトesnext
target                        -> esnextの直前の安定ECMAScriptバージョン
noUncheckedSideEffectImports  -> デフォルトtrue
libReplacement                -> デフォルトfalse
stableTypeOrdering            -> デフォルトtrue、そしてオフにできない
rootDir                       -> デフォルト ./ (内部のソースディレクトリは明示が必要)
types                         -> デフォルト [] (以前の挙動は ["*"])

発表文が「もっとも驚くべき」変更として挙げているのはrootDirtypesの二つです。どちらも緩和は簡単です。tsconfig.jsonsrcのようなディレクトリの外にあるプロジェクトは、ディレクトリ構造を維持したいならrootDirを明示すればよいだけです。

{
  "compilerOptions": {
    "rootDir": "./src"
  },
  "include": ["./src"]
}

typesのほうは、グローバル宣言に依存するプロジェクトが必要なものを自分で列挙する必要があります。

{
  "compilerOptions": {
    "types": ["node", "jest"]
  }
}

無害に見えますが、これが静かな地雷です。typesのデフォルトが[]になると自動探索が切れます — これまで@types/node@types/jestをインストールしておくだけで自動的に拾われることを期待していたなら、7では突然グローバルシンボルがないというエラーが降ってきます。コードが間違っているのではなく設定が変わったのであり、直し方も一行で済みますが、大きなモノレポでこれをパッケージごとに踏んでいくのは退屈な作業です。

strictがデフォルトtrueになったのも同様です。これまでnon-strictで生きてきたレガシーコードベースにとって、これは「コンパイラを変える作業」ではなく「型を書き直す作業」です。8倍速いコンパイラを手に入れるために、数か月分のstrictNullChecks作業を前払いしなければならない状況が生じ得ます。

そして完全になくなったもの — 無動作(no-op)ではなくハードエラーです。

  • target: es5のサポート終了
  • downlevelIterationのサポート終了
  • moduleResolution: nodeおよびnode10のサポート終了(nodenextまたはbundler推奨)
  • module: amdumdsystemjsnoneのサポート終了(esnextまたはpreserve推奨)
  • baseUrlのサポート終了(pathsをプロジェクトルート基準の相対パスに更新すること)
  • moduleResolution: classicのサポート終了
  • esModuleInteropallowSyntheticDefaultImportsfalseに設定不可
  • alwaysStrictは常にtrueとみなされfalseに設定不可
  • 名前空間宣言でmoduleキーワードを使用不可
  • importでassertsキーワードを使用不可 — ECMAScript import attribute構文に合わせてwithを使うこと
  • skipDefaultLibCheckのもとで/// <reference no-default-lib />ディレクティブがもはや尊重されない
  • カレントディレクトリにtsconfig.jsonがあるとコマンドラインビルドがファイルパスを受け取れない(--ignoreConfigフラグを明示しない限り)

このリストの中で実務を最も痛めるのはbaseUrltarget: es5です。baseUrlは古いプロジェクトの絶対パスimportに広く根を張っており、target: es5はまだ旧式ブラウザをサポートしなければならないチームにとって交渉不可能な要求になり得ます。es5が必要なら7はあなたのものではありません。これは設定を直せば越えられる種類の壁ではありません。

最後の項目も意外とよく踏まれます。npx tsc src/foo.tsのようなものをスクリプトに入れているチームがかなりありますが、プロジェクトルートにtsconfig.jsonがあると、今はただのエラーです。

本当のコスト(2) — APIがない、だからVue・MDX・Astro・Svelteは今日移行できない

これがGA発表文でもっとも重要なのに、もっとも引用されない部分です。

TypeScript 7.0は出たが、APIを出荷しない。

プログラミングAPIがありません。7.1で新しい(そして異なる)APIを出荷する見込みだと書かれており、それまでは6と7を並べて動かせるようにすることを優先したとのことです。

影響は直接的です。発表文の"TypeScript and Embedded Languages"節をそのまま移すと — Vue、MDX、Astro、Svelteなどを使うワークフローはまだTypeScript 7を活用できない可能性が高い。 Angularのようにテンプレート内部の特化した型チェックも同様です。理由は、7がまだ安定したプログラミングAPIを公開していないため、TypeScriptを自身のコンパイラや言語サービスに組み込むツール — Volarのような — が現時点ではTypeScript 6.0にしか依存できないからです。

これは「少し遅いかもしれない」ではなく使えないということです。フロントエンド生態系のかなりの部分がここに引っかかります。Vueチーム、Astroチーム、Svelteチーム、そしてMDXベースのドキュメント/ブログパイプラインは全部Volarの上に立っています。

推奨は次のように分かれます。

  • 言語サーバープラグインが不要なシナリオで7を使うこと — これが基本の推奨です。
  • Angular — CLIでtscによる高速なプロジェクト全体のエラー検出を行い、エディタサポートは6.0を使う組み合わせが可能です。つまり半分は手に入ります。
  • Vue、MDX、Astro、Svelteなど — 当面6.0を使い続ける必要があります。VS Codeでは"Disable TypeScript 7 Language Server"コマンドで6.0に戻せます。

Microsoftはこれを「特定時点の問題(point-in-time issue)」と捉えて解決策の提供を約束し、該当プロジェクトのメンテナーたちと積極的に協力すると述べています。信頼できる約束だと思います — ただし約束は今日のビルドを直してはくれません。 7.1の新APIが出て、Volarがそれに合わせて移植され、Vue/Astro/Svelteのツーリングがそれぞれ採用するまでには、リリースサイクルが何度も回ります。発表文自身が明かしているリリース周期は3~4か月ごとなので、ここにダウンストリームの採用時間がさらに加わります。

6と7を共存させる — tsc6とnpmエイリアス

だから現実的な答えはたいてい「両方置く」です。このためにMicrosoftが互換パッケージを新しく出しました。

@typescript/typescript6tsc6という実行ファイルを提供します。そのため、自分のtscバイナリを持ってくる7.0と名前の衝突なしに並べてインストールできます。このパッケージはTypeScript 6.0のAPIを再エクスポートもしているため、tscは7で使いながら他のツーリングは引き続き6.0に依存させることができます。npmレジストリで確認すると、このパッケージのlatest6.0.2で、binエントリはちょうどtsc6一つです。

typescript-eslintのようなツールはpeer dependencyを通じてtypescriptから直接importすることを期待するため、推奨される方法はnpmエイリアスです。

npm install -D typescript@npm:@typescript/typescript6

ただしこれだけだとtsc6実行ファイルしか残りません。7.0のtscも一緒に手に入れるには、エイリアスをもう一つかけます。

{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}

これでnpx tscは7.0で動作し、typescriptをimportするツールは6.0を見ます。

正直に言えばこれは優雅な解決策ではありません。package.jsonにエイリアスが二つ絡み合っており、typescriptという名前が実際には6を指している状態は、初めて見る人には確実に混乱します。しかしtypescript-eslintを使いながらtscは速く回したいなら — つまり現実の相当数のプロジェクトなら — 今のところこれが公式の道です。

静かに変わったこと — JSDocとUnicode

性能の見出しに隠れていますが、実際にコードを壊しうる変更がもう二つあります。

JavaScriptサポートが作り直されました。 もともとTypeScriptはJSDocコメントと特定のコードパターンを認識してJSファイルをサポートしていましたが、それはしばしばClosureやJSDocドキュメント生成ツールが理解していたものに基づく特殊ケースの塊でした。7.0はこれを.tsファイルの解析方式と一貫させて書き直しました。結果としてなくなったものがあります。

  • 型が来るべき場所に値を書けない — typeof someValueを使うこと
  • @enumがもはや特別扱いされない
  • 単独の?を型として使えない — anyを使うこと
  • @classが関数をコンストラクタにしない — クラス宣言を使うこと
  • 後置!未対応
  • 型名は@typedefタグの中で定義する必要がある(識別子の横に置く形は不可)
  • Closureスタイルの関数構文未対応 — TypeScriptの短縮形を使うこと

thisを別名で保持したり、関数のプロトタイプを丸ごと再代入したりするパターンも特別扱いがなくなりました。JSDocで型を付けた大きなJSコードベースを持っているなら、ここが本当の移行作業です。TypeScriptチームは6.0と7.0の差分をまとめたCHANGES.mdファイルを別途管理していると述べており、JSサポートはまだ流動的(in flux)だとしています。

テンプレートリテラル型がUnicodeコードポイントを保存します。

type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
type Result = HeadTail<"😀abc">;
//   TS 7.0では: ["😀", "abc"]
//   以前は:     ["\ud83d", "\ude00abc"]

以前はJavaScriptのUTF-16インデックス挙動に従ってサロゲートペアを半分に割っていました。技術的にはJSのインデックスと一貫していましたが、たいていは意図した挙動ではなく、意味のない不対サロゲートを含む文字列リテラル型が生まれることがありました。新しい挙動はfor...ofで走査したりスプレッドしたりするときの直感と一致します。

発表文はこれをUTF-16コードユニットを意図的にモデル化した型レベル文字列操作に対する破壊的変更だと正直にラベル付けしています — 一部の文字列Lengthユーティリティが例に挙がっています。型レベル文字列プログラミングを深く行うライブラリを使う、あるいは作っているなら確認が必要です。

もう一つ。--watchモードが完全に作り直されました。Parcelバンドラーのファイルウォッチャーを Goに移植したのが新しい基盤です(元々C++で全体のC++ツールチェーンが必要だったものを、最小限のアセンブリシムでGoに移しました)。Go標準ライブラリにファイル監視APIがなく、ポーリングベースの解決策はnode_modules依存の多い大規模プロジェクトでは高くつきすぎたというのが理由です。発表文はプラットフォーム全体で--watchのリソース使用量が大きく改善したと報告しています。

で、あなたは今日移行すべきか

まとめるとこう分かれます。

今日移行して価値がある場合

  • すでにTypeScript 6.0を使っており、stableTypeOrderingをオンにした状態でignoreDeprecationsなしでクリーンにビルドできる — これが公式の互換性文が保証する正確な条件です。この場合、移行はおおむね無難です。
  • 純粋な.ts/.tsxコードベースで、Volar系の組み込み言語ツーリングを使っていない。
  • CIの型チェックが実際のボトルネックである — 8倍はここで直接現金化されます。
  • エディタの応答性がチームの実質的な痛みである。

まだ移行できない場合

  • Vue、MDX、Astro、Svelteを使う — 選択の問題ではありません。7.1のAPIとその後のVolar移植を待つ必要があります。
  • Angular — 半分だけ可能です。CLIの型チェックは7、エディタは6。
  • target: es5が必要 — 壁です。
  • まだTypeScript 5.xでnon-strictである — 7に直接飛ばないでください。6をまず経由するのが公式の推奨であり、理由があります。廃止リストを一度に全部踏む代わりに、6で警告として受け取りながら整理できます。
  • typescript-eslintなどAPI依存のツーリングが中核のワークフローである — 先のエイリアスの組み合わせで可能ではありますが、その複雑さを引き受ける価値があるかはチームが判断すべき問題です。

そして順序についての助言を一つ。移行するなら--checkers値を明示的に固定してから始めてください。 ローカルとCIが異なるデフォルト並列度で動く状態で順序依存の診断差に出会うのは、デバッグしたくない種類のバグの筆頭です。チーム自身が「稀なケースだが現れうる」と書いている以上、値を固定するコストは一行で、固定しないコストは半日です。

おわりに

TypeScript 7.0の性能の話は本物です。ベンダー自己報告ではありますが、再現可能なオープンソースのコードベースで測定されており、条件(デフォルト--checkers 4、フルビルド)も公開されており、--checkers 8の表まで一緒に載せて数字が設定次第で動くことを自ら明かしています。ここまでやれば、ベンダーベンチマークとしては誠実な部類です。Slackの7.5分→1.25分のような数値が再現するなら、大きなコードベースではこれは生活の質の問題です。

しかし見出しは「10倍速くなった」であり、実際の話は「10倍速くなり、その代償として6の廃止リストを全部清算しなければならず、フロントエンド生態系の大きな一角はAPIが出るまで招待されていない」です。

だから私はこれをこう見ています — 7.0は完成した移行ではなく、始まった移行です。 7.1がAPIを携えて出て、Volarがその上に立つまで、この生態系はしばらく6と7に分かれて生きます。@typescript/typescript6tsc6という互換パッケージが存在すること自体が、それを認めていることの証です。Microsoftもこれを分かっており、だから発表文の最後で「7.1でどんな隙間も埋めてコミュニティを前へ連れて行きたい」と書いています。

あなたが純粋なTSコードベースなら、今日はよい日です。VueやAstroの上に立っているなら、今回のリリースはまだあなたのものではありません — そしてそれはあなたが何か間違えたからではありません。

参考資料