第57回ブログ:Node.jsでTypeScriptをネイティブ実行可能に ― Type Stripping機能の安定化とその背景

Node.jsでTypeScriptをネイティブ実行するイメージ図

はじめに:Node.jsがついに「TypeScriptネイティブ実行」の世界へ

2025年11月11日、Node.js v25.2.0がリリースされ、ついに TypeScriptコードをビルドなしでそのまま実行できる機能 (Type Stripping)が「Stable(安定版)」として正式にサポートされました。

これにより、DenoやBunに続き、主要なJavaScriptランタイムがすべてTypeScriptのネイティブ実行をサポートした状態になりました。 「ts-nodeや独自ローダーをかませて実行する」のが当たり前だった時代から、 「Node単体でそのまま実行できる」時代へと明確な転換点を迎えています。

本記事では、このType Stripping機能がどのような経緯で導入され、技術的に何をしているのか、そして開発体験にどのような影響を与えるのかを整理してみます。

1. Type Stripping機能導入のタイムライン

まずは、Node.jsにおけるTypeScriptサポートの流れを、ざっくり時系列で振り返ります。

2024年8月:Node.js v22.6.0 ― Type Strippingが実験的に登場

最初の一歩は、2024年8月リリースの Node.js v22.6.0 でした。

この段階ではまだ完全なTSサポートではなく、「型注釈を無視して実行できる最低限の仕組み」が提供された状態でした。

v22.7.0:enumなどを補う --experimental-transform-types の追加

その後の v22.7.0 では、型の削除だけでは対処できないTypeScript構文(後述)に対応するため、 --experimental-transform-types フラグが追加されました。

ただし、このフラグはあくまで実験的(experimental)であり、デフォルトで有効になることはありません。

2024年末〜2025年初頭:Node 22/23系でデフォルト有効化

その後、Type Stripping自体は徐々に本体へ統合されていきます。

2025年中頃:警告が消え、実質「安定運用」へ

2025年中頃のNode v24.3.0前後では、実験的機能の警告が削除され、 ドキュメント上はなお試験的でありながら、実質的には安定して使える段階へと移行しました。

2025年11月:Node.js v25.2.0でStable宣言

そして2025年11月、Node.js v25.2.0でついに Type Stripping機能が「Stable」指定となりました。

こうして約1年以上の段階的な検証を経て、Node.jsは「TypeScriptを直接扱えるランタイム」としての位置を確立しました。

2. Type Strippingの中身 ― 何をしていて、何をしていないのか

「TypeScriptがネイティブ実行できる」と聞くと、 「tsc不要?」「全部のTS構文が動く?」といった疑問が湧きます。 ここでは、Type Strippingが具体的に何をしているのかを整理します。

2-1. 基本方針:「型に関する部分だけを空白にして消す」

Type Strippingとは、その名の通り TypeScriptの型注釈や型専用の構文を実行時に取り除き、残りを素のJavaScriptとして実行する仕組み です。

Node.jsは .ts ファイルを読み込む際、型に関する部分を 「空白文字に置き換える」 ことで削除します。

ポイントは 「型チェックは一切しない」 ことです。 つまり、これは「コンパイラ」ではなく「高機能なプリプロセッサ」に近いイメージです。

2-2. 外部ライブラリ「Amaro」とSWCベースの実装

Node.jsは、この型除去処理を自前で1から実装したわけではありません。 内部的には 「Amaro」 と呼ばれるツールを取り込み、 その裏側で 高速なTypeScriptパーサであるSWC を利用しています。

Bloomberg社の「ts-blank-space」と同系統のアプローチで、 「とにかく軽くて邪魔しない」型除去 を目指した設計になっています。

2-3. 「消せる型」と「消せないTypeScript構文」

もちろん、TypeScriptのすべての構文が空白に置き換えられるわけではありません。 Node.jsが対応しているのは、 「消しても実行時に問題がない純粋な型情報」 に限られます。

代表的なサポート外(=そのままでは動かせない)構文は次の通りです。

こうした構文は、従来通り tscでコンパイルするか、 または --experimental-transform-types を併用する必要があります。

2-4. --experimental-transform-types の位置づけ

--experimental-transform-types は、Type Stripping単体では扱えない構文を 限定的にJSへ変換するオプションです。

Node.jsチームの基本方針は、「デフォルトは軽い型除去のみに留める」 ことであり、 フル機能TSコンパイラになることは目指していません。

3. 実際に使うときの注意点

「NodeでTSが動くようになった!」と言っても、 プロジェクトに適用する際にはいくつかの落とし穴があります。 ここでは、特に重要なポイントを整理します。

3-1. 型チェックは別途 tsc --noEmit などで回す必要がある

繰り返しになりますが、Type Strippingは 型チェックをしません

つまり「ビルドが不要になった」のではなく、 「実行のためのトランスパイルが不要になった」 と理解するのが良いでしょう。

3-2. tsconfig.jsonはNode実行時には無視される

NodeによるType Stripping実行では、tsconfig.jsonは参照されません

パスエイリアスを使いたい場合は、Nodeの サブパスインポート("#alias"形式) など、Node標準の仕組みに寄せていく必要があります。

3-3. モジュール種別の判定と拡張子の扱い

Nodeは、拡張子と package.json"type" フィールドの組み合わせで ES Modules / CommonJS を判定します。

これは「ビルド前提」で import "./foo.js" と書いていた従来のTSプロジェクトと 互換性がありません。
「Nodeで直接実行するTS」は、最初からNodeの解決ルールに沿った書き方にしておく のが安全です。

3-4. import type を正しく使わないと実行時エラーになる

TypeScriptでは、型だけをインポートする場合に import type が使えます。 NodeのType Strippingでは、これを正しく使うことがほぼ必須になります。

TypeScript 5.0以降では verbatimModuleSyntax を有効にすることで、 こうした問題のあるインポートをコンパイル時に検知しやすくなります。

3-5. node_modules内の .ts は実行しない(ライブラリ配布には非推奨)

もう1つ重要な仕様として、Nodeは node_modules 内の TypeScriptファイルを実行しません

したがって、 「ライブラリはコンパイルして配布」「アプリ本体の開発体験向上にType Stripping利用」 という役割分担を意識しておく必要があります。

4. 開発体験(DX)へのインパクト

ここからは、「で、実際どれくらい嬉しいの?」という視点でメリットを整理してみます。

4-1. ビルド無しの「書いてすぐ実行」

最も分かりやすいメリットは、「実行のためのビルドが不要になる」ことです。

といった場面では、トランスパイルの待ち時間がゼロになり、 「保存 → すぐnodeで起動」というサイクルが実現します。

4-2. ツールチェーンの簡素化

これまではTypeScriptでNodeアプリを開発しようとすると、例えば次のような構成になりがちでした。

現在のNodeは --watch オプションも持っているため、 「NodeだけでTypeScriptの編集〜実行〜自動再起動まで完結」 させることができます。

これにより、 「ツールが多すぎて新人にセットアップを説明するのが大変」 といった問題をかなり緩和できるでしょう。

4-3. パフォーマンスとCI/CDの軽量化

Type Stripping自体は非常に軽量な処理なため、 従来の「トランスパイル → 実行」よりもオーバーヘッドが少ない という利点があります。

4-4. 「挙動はほぼ生のJavaScript」という安心感

Type Strippingは、型を消す以外はほとんど何もしません

そのため、「実行時はほぼ純粋なJavaScriptの世界」 でありながら、 開発時にはTypeScriptの型安全性も享受できるという、いいとこ取りの感覚で使えます。

5. 開発者コミュニティの反応

実際のところ、この機能に対する開発者の反応はどうだったのでしょうか。

5-1. 概ね歓迎ムード:「これでようやく追いついた」

発表当初、SNSやコミュニティでは

「ついにNodeでもトランスパイルなしでTSが動く」
といった声が多く見られました。

5-2. 実運用でのフィードバック:「ローカルとCIで問題なく使えている」

早期から実サービスに導入した開発者からは、次のような報告も上がっています。

実際、Type Stripping自体はv22〜24の間に相当こなれており、 v25.2.0でのStable宣言は「中身が大きく変わった」のではなく「十分に枯れたので看板を変えた」 というニュアンスに近い印象です。

5-3. 慎重派の意見:「enumや特殊構文を多用するなら様子見」

一方で、次のような慎重な声もあります。

ただし、そのようなケースでも、 --experimental-transform-types の活用や、部分的な導入(ツール系だけNode直実行にする等)で 折り合いをつけている例も見られます。

6. 今後の展望 ― JavaScript標準との接続とTypeScriptエコシステム

最後に、「この先どうなっていきそうか」という視点で少し未来を眺めてみます。

6-1. --experimental-transform-types の今後

Node.jsチームは、当面は 「デフォルト:型除去のみ」「追加機能:transform-types」 という二段構えを維持すると見られています。

実装者のひとりであるMarco Ippolito氏も、 「あくまで軽量な型除去がデフォルト路線」 であることを明言しており、 Nodeが「TSコンパイラ」に化けることはなさそうです。

6-2. TC39の「型注釈を言語レベルで許容する」提案との関係

JavaScript標準化委員会(TC39)では現在、 「型注釈を言語として許容しつつ、実行時には無視する」 という方向性の提案が議論されています。

これは、TypeScriptやFlowの型構文を「コメント的」に扱うイメージで、 実現すればブラウザを含むすべてのJSエンジンが 「型情報を読み飛ばして実行」できるようになります。

NodeのType Strippingは、ある意味でこの世界観を先取りした実装と言えます。 もし将来標準仕様として「型注釈OK、ただし実行時は無視」という形が採用されれば、 ブラウザでも「TSをそのまま読み込む」世界が現実味を帯びてきます。

6-3. TypeScript本体やツール側の追随(--erasableSyntaxOnly など)

TypeScript本体や周辺ツールも、NodeのネイティブTS実行を前提とした機能追加を進めています。

こうした動きにより、 「NodeでTSをネイティブ実行する」ことが前提のプロジェクトも 今後増えていきそうです。

6-4. ランタイム間の差は「TypeScript対応」から「周辺体験」へ

Deno・Bun・NodeのすべてがTSネイティブ対応になったことで、 ランタイム選びの軸は、

といった「周辺体験」に移っていきます。

Nodeはnpmエコシステムの中心として、 「既存資産を最大限活かしつつ、TS時代に追随した」 というポジションを強めていくことになるでしょう。

まとめ:Node.js開発者として、どう付き合っていくか

最後に、Node.jsで開発する立場から、 Type Strippingをどう活用していくと良さそうか を簡単にまとめます。

個人的には、「TypeScriptを使い始めるハードルを大きく下げてくれる機能」だと感じています。 tscやBabelの設定を覚える前に、 「とりあえず node main.ts してみよう」と言えるのは、 学習者にとってもチームにとっても大きなメリットです。

これからNode.jsでTypeScriptを書くときは、 「どこまでをNodeネイティブ実行に任せ、どこからを従来のビルドに任せるか」 を意識して設計していくと、DXと安全性のバランスが取りやすくなるはずです。

← ブログTOPへ戻る