TypeScript 7.0 発表
(devblogs.microsoft.com)- TypeScript 7.0は、ツールチェーンをGoベースのネイティブコードへ移植したリリースで、大規模プロジェクトのフルビルドで通常 8〜12倍の高速化を実現する
- 新しい
tscは従来どおりnpmのtypescriptパッケージとしてインストールでき、エディタ対応は LSPベースの言語サーバーとしてVS Code、Visual Studio、WebStormなどで動作する vscode、sentry、bluesky、playwright、tldrawのようなコードベースでビルド時間が大幅に短縮され、一部の環境では総メモリ使用量も低下した- TypeScript 7.0にはまだ安定したプログラミングAPIがないため、
typescript-eslint、Vue、MDX、Astro、Svelte、Angularテンプレートの型チェックなど、TypeScriptを組み込むツールではTypeScript 6.0との併用が必要になる - 新しいデフォルト値と削除されたオプションがあるため、まずTypeScript 6.0の変更点を適用しておくほうが移行に有利で、TypeScript 7.1で新APIの提供が予定されている
GoベースのネイティブTypeScript
- TypeScript 7.0はTypeScriptツールチェーンのネイティブ移植版で、Goで書かれた新しいコードベースを使用する
- 既存コードベースの構造とロジックをできる限り維持し、2つのコンパイラ間で結果の一貫性と互換性を合わせる方針で移植された
- 新しいコードベースは、ネイティブコードの速度、共有メモリベースのマルチスレッド、複数の最適化により、フルビルドで通常 8〜12倍高速な結果を出す
- インストールは従来どおりnpmで可能
npm install -D typescript
- インストール後、ワークスペースで新しい
tsc実行ファイルを利用でき、npx tscで実行できる
開発フィードバックループの短縮
- TypeScriptは、エディタの読み込み、全参照検索、オートコンプリート、診断、
tsc、--watchモードなど、開発プロセスのさまざまな段階に関わる - TypeScript 7は、このプロセス全体の待ち時間を減らし、フィードバックループを短くする
- VS Codeコードベースでエラーのあるファイルを開いたとき、最初のエラーが表示されるまでの時間は約17.5秒から1.3秒未満に短縮され、13倍以上高速化した
- エディタ対応はLSPベースで、新しい言語サーバーはマルチスレッドを活用して同時リクエストを高速に処理する
- VS CodeユーザーはTypeScript 7専用拡張機能をインストールでき、今後数週間以内にVS Code本体にもTypeScript 7対応が含まれる予定
- Visual Studioの最新バージョンは、ワークスペースに応じてTypeScript 7を自動的に有効化する
ビルド性能とメモリ結果
- TypeScript 6と7を大規模オープンソースコードベースで比較したフルビルド時間は以下のとおり
| コードベース | TypeScript 6 | TypeScript 7 | 高速化 |
|---|---|---|---|
| vscode | 125.7秒 | 10.6秒 | 11.9倍 |
| sentry | 139.8秒 | 15.7秒 | 8.9倍 |
| bluesky | 24.3秒 | 2.8秒 | 8.7倍 |
| playwright | 12.8秒 | 1.47秒 | 8.7倍 |
| tldraw | 11.2秒 | 1.46秒 | 7.7倍 |
- 同じビルドで、TypeScript 7はおおむね総メモリ使用量もより低かった
| コードベース | TypeScript 6 | TypeScript 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% |
実際のコードベースでの検証とチームからのフィードバック
- TypeScriptプロジェクトは、10年以上にわたって蓄積された数万件のテストを、すべての
mainブランチのコミットで実行している - TypeScript 7は、これらのテストに加え、社内外の大規模チームの実際のコードベースでも検証された
- Microsoft社内では、Loop、Office、PowerBI、Teams、XboxチームがTypeScript 7を検証した
- 社外では、Bloomberg、Canva、Figma、Google、Lattice、Linear、Miro、Notion、Sentry、Slack、Vanta、Vercel、VoidZeroなどがコードベースでテストし、フィードバックを提供した
- 新しい言語サーバーはTypeScript 6.0比で、失敗した言語サーバーコマンドを80%以上、サーバークラッシュを60%以上削減した
- 実際のチームからのフィードバックには、以下の事例が含まれる
- SlackはTypeScript 7によりmerge queueの時間が40%短縮され、CIの型チェック時間が約7.5分から1.25分に下がったと伝えた
- Vantaは大規模プロジェクトの1つで最大9倍のビルド高速化を示した
- Microsoft News ServicesチームはCIビルドの待ち時間を月400時間削減した
- Canvaは、エディタで最初のエラーが表示されるまでの時間が約58秒から4.8秒に短縮されたと伝えた
TypeScript 6.0との併用実行
- TypeScript 7.0はまだAPIを含まない
- TypeScript 7.1で新しく異なるAPIを提供する予定
- それまでは、コンパイラへのプログラミングアクセスが必要なツールのために、TypeScript 6.0と7.0を併用実行できる
- 新しい互換性パッケージ
@typescript/typescript6はtsc6実行ファイルを提供し、TypeScript 6.0 APIを再エクスポートする typescript-eslintのようにpeer dependencyとしてtypescriptを直接importするツールには、npm aliasの使用を推奨する
npm install -D typescript@npm:@typescript/typescript6
- TypeScript 6 APIとTypeScript 7の
tscを一緒に使うには、次のようにaliasを設定できる
{
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2"
}
}
- 既存の
@typescript/native-previewパッケージは、TypeScript 7の新コードベースのnightlyビルドを提供してきており、週間ダウンロード数は850万回以上だった - 今後、nightlyビルドは標準の
typescriptパッケージのnextタグで再開される予定
npm install -D typescript@next
並列化制御オプション
-
TypeScript 7.0は、パース、型チェック、emitなど複数の段階を並列実行する
-
パースとemitはファイルごとに独立実行しやすく、大規模コードベースで比較的少ないオーバーヘッドでスケールする
-
新しい実験的フラグ
--checkers、--builders、--singleThreadedが並列化の動作を調整する -
--checkers- TypeScript 7.0は固定数の型チェックワーカーを作成し、同じ入力ファイルに対して常に同じように作業を分割して同一の結果を出すようにする
- デフォルトの型チェックワーカー数は4個で、
--checkersで調整できる --checkers 8を使った同じマシンでの結果は以下のとおり
コードベース TypeScript 6 TypeScript 7 --checkers 8高速化 vscode 125.7秒 7.51秒 16.7倍 sentry 139.8秒 12.08秒 11.6倍 bluesky 24.3秒 2.01秒 12.1倍 playwright 12.8秒 1.16秒 11倍 tldraw 11.2秒 1.06秒 10.6倍 -
--checkersを増やすと、より多くのCPUコアを活用してビルドが速くなる可能性があるが、通常はメモリ使用量の増加を伴う- CPUコアとメモリが少ないCI runnerでは、値を下げて不要なオーバーヘッドを避けられる
--checkers 1は型チェックを実質的にシングルスレッド化し、重複作業をなくす- まれに、
--checkers数の変化が順序依存の結果を露呈させることがあるため、ビルド環境全体で固定のchecker数を指定する方法が役立つ場合がある
-
--builders--buildersは、--build実行時に同時実行できるプロジェクト参照ビルダーの数を制御する- プロジェクト数の多いmonorepoで特に役立つ可能性がある
- 値を増やすとビルドが速くなる可能性があるが、メモリ使用量も増えることがある
--checkersとの乗算効果があり、--checkers 4 --builders 4では最大16個の型チェッカーが同時に実行される可能性がある--builders数の変化は、--checkersとは異なり、異なる結果を生んではならない- プロジェクト参照ビルドは基本的にプロジェクトの依存関係グラフによってボトルネックが生じる
-
--singleThreaded--singleThreadedはコンパイラ全体をシングルスレッドで実行させる- デバッグ、TypeScript 6と7の性能比較、外部の並列ビルドオーケストレーション、リソースが非常に限られた環境で有用な場合がある
- このフラグは型チェックワーカー数を1に制限するだけでなく、パースとemitもシングルスレッドで実行させる
新しい--watchモード
- TypeScript 7は
--watchモードを全面的に作り直した - 新しい
--watchはParcel bundlerのfile-watcherをベースに、効率的で安定したクロスプラットフォームのファイル監視機能を提供する - Go標準ライブラリには組み込みのファイル監視APIがなく、検討したサードパーティライブラリには安定性、性能、クロスプラットフォーム対応、ビルドツール統合の面で問題があった
- 純粋なpolling方式は複数のOSで動作したが、
node_modules依存関係の多い大規模プロジェクトでは計算コストが大きかった - TypeScriptチームはVS Codeで使われてきた
@parcel/watcherをGoに移植し、C++ツールチェーン依存を避けるため最小限のアセンブリshimを使っている - このwatcherは独立したパッケージであり、TypeScript 7の
--watchモードでプラットフォーム全体のリソース使用改善をもたらす
TypeScript 6.0のデフォルト値と互換性の変更
- TypeScript 7.0は、TypeScript 6.0の型チェックとコマンドライン動作と互換になるよう作られている
stableTypeOrderingフラグが有効で、ignoreDeprecationsが設定されていない状態でTypeScript 6.0でクリーンにコンパイルされるコードは、TypeScript 7.0でも同じようにコンパイルされるはずである- TypeScript 7.0はTypeScript 6.0の新しいデフォルト値を採用し、TypeScript 6.0でdeprecatedになったフラグと構文にはhard errorを出す
- 主な設定デフォルト値の変更は以下の通り
strictのデフォルトはtruemoduleのデフォルトはesnexttargetのデフォルトはesnext直前の現在の安定版ECMAScriptnoUncheckedSideEffectImportsのデフォルトはtruelibReplacementのデフォルトはfalsestableTypeOrderingのデフォルトはtrueで、無効化できないrootDirのデフォルトは./typesのデフォルトは[]で、以前の動作は["*"]で復元できる
rootDirとtypesの変更が、最も意外に感じられる可能性のある変更とされるtsconfig.jsonがsrcのようなソースディレクトリ外にあるプロジェクトでは、既存のディレクトリ構造を維持するためにrootDirを明示する必要がある- 特定のグローバル宣言に依存するプロジェクトでは、必要な
@typesパッケージをtypesに明示する必要がある
{
"compilerOptions": {
"rootDir": "./src"
},
"include": ["./src"]
}
{
"compilerOptions": {
"types": ["node", "jest"]
}
}
削除された、またはhard errorになった動作
- TypeScript 7.0では、TypeScript 6.0でdeprecatedとなった複数のオプションと構文がサポートされなくなった
- 主な項目は以下の通り
target: es5は未サポートdownlevelIterationは未サポートmoduleResolution: node/node10は未サポート、nodenextとbundlerを推奨module: amd, umd, systemjs, noneは未サポート、bundlerまたはブラウザベースのモジュール解決とともにesnextまたはpreserveを推奨baseUrlは未サポート、pathsはbaseUrlの代わりにプロジェクトルート基準の相対パスへ更新可能moduleResolution: classicは未サポート、bundlerまたはnodenextを推奨esModuleInteropとallowSyntheticDefaultImportsはfalseに設定できないalwaysStrictはtrueと見なされ、falseに設定できない- namespace宣言で
moduleキーワードは使用不可 - importで
assertsキーワードは使用不可、ECMAScript import attribute構文の変更に合わせてwithを使う必要がある skipDefaultLibCheckの下で、/// <reference no-default-lib />ディレクティブはもはや尊重されない- 現在のディレクトリに
tsconfig.jsonがある場合、コマンドラインビルドでファイルパスを受け取れず、明示的な--ignoreConfigが必要
テンプレートリテラル型とJavaScriptサポートの変更
- TypeScript 7.0は、テンプレートリテラル型の推論でUnicode code pointをより自然に扱う
type HeadTail<S> = S extends `${infer Head}${infer Tail}` ? [Head, Tail] : never;
type Result = HeadTail<"😀abc">;
// 7.0: ["😀", "abc"]
// 以前: ["\ud83d", "\ude00abc"]
- 以前はJavaScriptのUTF-16 indexing動作に従い、
"😀"をsurrogate pairの2つの部分に分けていた - 新しい動作は、
for...ofや[...str]のように"😀"を1つの単位として扱う直感に沿っている - UTF-16 code unitを意図的にモデル化した型レベルの文字列操作にはbreaking changeになり得る
- JavaScriptサポートは、TypeScriptファイルの解析方法とより一貫するよう再設計された
- 型の位置で値は使用できず、
typeof someValueを使う必要がある @enumはもはや特別扱いされない- 単独の
?は型として使用できず、anyを使う必要がある @classは関数をコンストラクタにせず、class宣言を使う必要がある- postfix
!はサポートされない - 型名は
@typedefタグ内で定義する必要がある - Closureスタイルの関数構文はもはやサポートされず、TypeScriptの省略構文を使う必要がある
- 型の位置で値は使用できず、
thisのaliasingや関数prototype全体の再代入のような一部のJavaScriptパターンも、もはや特別扱いされない- TypeScript 6.0と7.0の違いは
CHANGES.mdにさらに詳しくまとめられている
エディタ機能と制限
- TypeScript 7.0には、ベータ以降に不足していた複数のエディタ機能が追加された
- 自動インポート、拡張可能な hover、inlay hint、code lens、go-to-source-definition、JSX linked editing、tag completion などが含まれる
- semantic highlighting、「sort imports」、「remove unused imports」など、TypeScript 7.0 betaで欠けていた機能も含まれる
- 言語サーバーの品質向上のため、テストと診断インフラを再構築し、GitHub上の主要な TypeScript・JavaScript コードベースを対象に fuzz test を実行できる
組み込み言語ワークフローの現時点での制約
- Vue、MDX、Astro、Svelte などを使用するワークフローは、まだ TypeScript 7 を活用できない可能性が高い
- Angular テンプレートのような特殊なテンプレート型チェックも、TypeScript 7 を使用できない可能性が高い
- 主な理由は、TypeScript 7 がまだ安定した プログラミング API を公開していないため
- Volar のように TypeScript を独自のコンパイラや言語サービスに組み込むツールは、現時点では TypeScript 6.0 に依存せざるを得ない
- TypeScript チームはこの問題を特定時点での制約と見ており、該当プロジェクトのメンテナーと協力して TypeScript 7 対応を確保する計画
- それまでは、language server plugin が不要なシナリオで TypeScript 7 の使用を推奨する
- Angular プロジェクトでは、CLIでプロジェクト全体のエラーを高速に検出するために TypeScript 7 の
tscを使い、エディタ支援には TypeScript 6.0 を併用できる - Vue、MDX、Astro、Svelte などは、当面 TypeScript 6.0 を使い続ける必要がある
- VS Code では「Disable TypeScript 7 Language Server」コマンドで TypeScript 6.0 に戻せる
今後の計画
- TypeScript 7.0 のリリースは、TypeScript プロジェクトが1年以上注力してきたネイティブ移植における主要なマイルストーン
- 7.0以降は、新機能の開発、使いやすさの改善、さらなる性能向上、エコシステム向けの新API実装に戻る予定
- TypeScript 7.0以前と同様に、3〜4か月ごとに新機能リリースを出す見込み
- TypeScript 7.1では、コミュニティの移行を支援するためのギャップ解消と新APIの提供が予定されている
2件のコメント
Hacker Newsでの意見
独自テスト基準での TypeScript 7 の速度向上は次のとおり
責任ある形でマイグレーションしながらこれだけの成果を出したチームはすごい。Bunも少し見習ってほしい。気になるのは、tsdownやesbuildのようにTypeScriptコードベースをビルドする下位ツールにどんな影響があるのか、TS 7 と現在のtsdownを併用できるのかという点
--isolatedDeclarationsを使っているかどうかによるし、そうでないならブログの案内どおり TypeScript 6 を並行インストールすればよい以前は型は費やす労力ほどの価値がない、と議論していた時代もあった。TypeScriptが優れている理由は、何よりも 型を大衆化した ところにある
たとえば「Pythonは型がないから使えない」というような話も何度も聞いたが、それは正しくない。Pythonは強い型付けの言語であり、同時に動的型付けの言語であるだけだ。
本当に型がない、あるいは普通「文字列ベースの型付け(stringly typed)」と呼ばれる言語もある。子どもの頃に触っていたAREXXは、数値のように見えてもすべての値が文字列だったし、sedのようなUnix CLIツールの多くもそう見なせる。しかし型に関する議論の大半はPythonのような動的型付け言語をめぐるもので、弱い型付けや無型の言語が大規模プロジェクトに向いていると言う人はほとんど見たことがない。むしろPythonを「型がない」と誤って呼び、大規模プロジェクトには使えないと言う話を多く聞いたし、実際にPythonで大規模プロジェクトを作っていた立場からすると混乱させられた
以前に触れる型といえばC++/Javaがほとんどで、特にC++は過度に複雑な言語を作る方法以外では、何かの良い例とは言いにくい。型がうまく適用された姿を一度見れば、はるかに説得しやすい
ここで本当に印象的なのは、人類が知る最も進んだ型システムのために、2つの別々のコードベースを同時に保守した優れたチームだ。Rustでの再実装も期待している
Rustは開発時間がはるかに長くなるはずだ。RustがGoより20%速い可能性はあっても、TypeScriptからGoで得た向上だけでも十分大きい。vscodeでGoの11倍の代わりにRustなら14倍になるかもしれないが、Goだけでもすでに大きな差を生むには十分
TypeScriptの型システムをけなす意図ではなく、実際とても興味深い取り組みだ
数年TypeScriptを使ってからだと、Pythonで型アノテーションを手で付けたり、
abcのような基本的な言語機能を取り込まなければならなかったりするのが本当に面倒に感じる興味深いが、今はNodeがTypeScriptの型アノテーションをネイティブに削除するので、TSC はほとんど実行していない。大きな回帰変更を作ってしまい、更新できていない部分をコンパイラの静的な出力で確認する必要がある時くらいしか回さない
ブラウザに行くフロントエンドコードもNodeの型削除に依存している
JSDocの型構文 が引き続き注目されているのはうれしい。個人プロジェクトでTypeScriptを使う一番好きな方法だ。一部の構文変更は更新が面倒だろうが、ほとんどは改善の方向に見える
[1] https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
TypeScript の大きな苦痛は、プロジェクトの一部に対して
libやtypesのような tsconfig 設定の適用範囲を調整しにくい点にあるプロジェクトは Web アプリなのに、
vite.config.ts、Playwright、単体テストのせいで IDE ツール側に Node 型が入り込んでいる。React コンポーネントに Node API を追加してもtscが文句を言わない。現状、DOM ライブラリと Node ライブラリを分離しようとすると、プロジェクト参照のスパゲッティ、大量の
tsconfig.jsonとtsbuildinfo出力ファイルが必要になり、プロジェクト参照を使いながら型出力を避けるのも面倒単一アプリケーションでも nx を好んで使っており、共有コードは「ライブラリ」に移している。ビルドしないライブラリを使っているが、大きなプロジェクトではかなり良い
まだ TypeScript コンパイラ API はないが、作業中とのことなので期待している
メモリ使用量は減り、性能は大きく上がっているグラフを見ると、サーバー側では TypeScript ではなく Go を使うべきなのではと思ってしまう
それに、今は選択肢があるのに TS/JS/Python で新規プロジェクトを始める人がなぜいるのかは、正直よく分からない
TypeScript チーム、おめでとう。長めの文章や音声で投稿したい内容はあるが、短く言うと JavaScript/TypeScript エコシステムは 木材で作業することに似ている
安物のラミネート合板材や、Ikea 風のものも作れる。コードで言えば、独創性のないバイブコーディングアプリのようなものだろう。
逆に、高級な手作り家具や木造高層建築も可能だ。若い木材を使い、カスタム接合やラミネーション技法で耐火性のある梁を作るようなものだ。JavaScript/TypeScript エコシステムでも、AI を強力な工作機械のように使いながら、職人精神を持って作る高品質な成果物が生まれ得る。何かを作って実行する勇気があるなら、TypeScript/JavaScript エコシステムを受け入れればよい
Lobste.rs のコメント
理由は理解できるが、セルフホスティングのコンパイラからセルフホスティングではないコンパイラへ移行した点が興味深い
通常はほぼ常に逆方向へ進むため、珍しい流れだ
セルフホスティングは、その言語がコンパイラをより書きやすい言語へ進化するよう強い圧力をかけるが、それが常に正しい方向とは限らない
TypeScript でコーディングしていなくても、VSCode 自体が TypeScript で書かれているので、この改善がVSCode の速度にも影響するのか気になる
それとも TypeScript 言語拡張だけに影響するのか気になる
ここで速くなるのは、TypeScript コードを受け取って JavaScript に変換するコンパイラだけで、この過程は Microsoft が VSCode の実行ファイルを配布する前のビルドパイプラインで行われる
潜在的な例外があるとすれば TypeScript LSP サーバーも速くなる可能性がある、という程度で、これは実際に実行中に TypeScript コードをパースするためだ。ただし、VSCode が TypeScript で書かれているという事実とは別の話だ
tscは型の削除のような最小限の処理を除き、処理中のコードに手を入れてはいけないという原則があるため、WONTFIX とされているものがかなりあるそのため、TypeScript で作られたツールの性能特性はほとんど変わらないと予想している
個人的に得た小さな tips。現在担当しているプロジェクトは TS 5 を使っているが、予想どおり nvim ではそれを使いたくなかった
そこでまず mise で TS 7 をインストールし、
node_modules/.binの中に mise でインストールした TS を指すtsgoシンボリックリンクを作ったnvim-lspconfig が今でも技術プレビュー時代の古い
tsgoファイル名を使っているため、nvim がローカルの TS ではなく、インストールしておいた TS 7 を実行するようになる