Node.js v25.2.0でTypeScriptがネイティブ実行可能に

Node.js v25.2.0でTypeScriptがネイティブ実行可能に

最終更新日:2025年12月06日公開日:2025年12月06日
益子 竜与志
writer:益子 竜与志
XThreads

「TypeScriptを書いたらそのまま実行できたらいいのに」——そう思ったことがある人は多いはず。Node.js v25.2.0でついにType Stripping機能が安定版に到達し、トランスパイルなしでTypeScriptファイルを直接実行できるようになりました。この記事では、実際の動作原理から実務での使いどころまで解説します。

Type Strippingってそもそも何?

Type Strippingは、TypeScriptファイルから型情報だけを削除して、残ったJavaScriptコードを実行するアプローチです。従来のtscによるトランスパイルとは根本的に発想が違っていて、「型注釈をスペースで置き換える」というシンプルな手法を取っています。

Type Strippingプロセス

具体的にはこんな感じです。

// 元のTypeScript
const greeting: string = "Hello";
function add(a: number, b: number): number {
  return a + b;
}

// Type Stripping後
const greeting         = "Hello";
function add(a        , b        )        {
  return a + b;
}

型の部分がスペースに置き換わっているのがわかりますよね。この方法のメリットは、行番号がオリジナルコードと完全に一致すること。つまりソースマップが不要になり、スタックトレースがそのまま読めるんです。

なぜ今まで時間がかかったのか

この機能、実は2024年8月のNode.js v22.6.0から実験的機能として存在していました。そこから約1年半かけて、段階的に安定化が進められてきたわけです。

振り返ってみると、v22.7.0でenumやnamespaceの変換サポートが追加され、v22.18.0でデフォルト有効化、そしてv25.2.0でついにStable(安定版)に昇格。このペースを見ると、Node.jsチームがかなり慎重に進めてきたことがわかります。

個人的には、この慎重さは正解だったと思います。TypeScriptはエコシステムの中核技術になっているので、中途半端な実装で問題が起きると影響範囲が広すぎる。

技術的な仕組みを深掘りする

内部実装としては、amaroというローダーが使われていて、これはSWCのTypeScriptパーサー(WebAssembly版)をラップしたものです。SWCはRust製の高速コンパイラなので、処理速度は従来のtscと比較にならないくらい速い。

具体的な数字を出すと、Bloombergが開発したts-blank-space(Type Strippingの参照実装)の計測では、52,000行のTypeScriptファイルのコンパイルがtscの5.6倍速かったそうです。

この速度差の理由はシンプルで、従来のtscが「解析→変換→コード生成」の3ステップを踏むのに対し、Type Strippingは「型情報の削除」という1ステップだけで完結するから。型チェックもやらない、コード変換もしない、ただ消すだけ。

使えるTypeScript構文と使えない構文

ここが実務で一番気をつけるべきポイントです。Type Strippingで処理できるのは「削除可能(Erasable)な構文」だけ。

処理できる構文としては、インライン型注釈(const x: number)、インターフェース定義、型エイリアス、ジェネリック型パラメータ、import typeステートメントなど。基本的な型定義はほぼカバーされています。

一方、enumやランタイムコードを含むnamespaceは「非削除可能(Non-erasable)」とされていて、デフォルトではエラーになります。これらを使いたい場合は--experimental-transform-typesフラグが必要です。

また、.tsxファイル(JSX)とDecorator構文は現時点で非サポート。特にReactプロジェクトでは、TSXが使えないのは痛いかもしれません。

実務での使い方

開発環境での型チェックはNode.js側では一切実行されないので、別途tscを走らせる必要があります。

# 型チェック(IDE統合またはCI/CDで実施)
tsc --noEmit

# ファイル実行
node script.ts

推奨されるtsconfig.jsonの設定はこちら。

{
  "compilerOptions": {
    "noEmit": true,
    "target": "esnext",
    "module": "nodenext",
    "rewriteRelativeImportExtensions": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true
  }
}

erasableSyntaxOnlyはTypeScript 5.8で導入された新しいオプションで、これを有効にすると非削除可能な構文(enum等)を使った時点でtscがエラーを出してくれます。Node.jsのType Strippingと互換性のあるコードだけを書くよう強制できるわけです。

型インポートの書き方に注意

地味だけど重要なのが、型をインポートする時にtypeキーワードを明示的に使う必要があること。

// 正しい書き方
import type { User, Admin } from './types.ts';
import { getUserData, type UserResponse } from './api.ts';

// ダメな書き方(ランタイムエラー)
import { User, Admin } from './types.ts';

typeキーワードがないと、Node.jsはそれを値インポートと判定してしまい、結果的にランタイムエラーが発生します。既存プロジェクトに適用する場合、ここの修正が一番手間かもしれません。

node_modules内のTSファイルは対象外

これは意図的な設計です。node_modules配下のTypeScriptファイルは処理対象外になっています。

理由は明確で、パッケージ作者に対して「TypeScriptで配布するな、トランスパイル済みJavaScriptで配布しろ」というメッセージ。実際、npm配布パッケージでtsファイルをそのまま配布しているケースは少ないので、実務上はあまり問題にならないと思います。

どんな場面で使うべきか

正直、本番環境でバリバリ使うにはまだ早い気がしています。特にReactプロジェクト(TSX非対応)や、enumを多用しているプロジェクトでは厳しい。

一方で、CLIツールの開発やスクリプト実行、プロトタイピングには最適です。node script.tsと打つだけで動くのは、やっぱり体験として良い。

あとはts-nodeやtsxに比べて圧倒的に起動が速いので、ファイル監視付きの開発サーバーを回すような場面では恩恵を感じられるはず。

TypeScript 5.7/5.8との連携

TypeScript側もNode.jsのType Strippingに歩み寄る形で機能追加を進めています。

5.7で追加された--rewriteRelativeImportExtensionsは、相対パスの.ts拡張子を.jsに自動書き換えしてくれるオプション。ライブラリ作者がTypeScriptソースから.jsファイルを出力してnpm配布する時に便利です。

5.8の--erasableSyntaxOnlyは前述の通り、非削除可能な構文を禁止するオプション。この2つを組み合わせることで、Node.jsネイティブ実行と従来のnpm配布の両立が現実的になってきました。

まとめ

  • Node.js v25.2.0でType Stripping機能が安定版に到達
  • 型情報をスペースに置き換えるシンプルな仕組みで、ソースマップ不要
  • enumやnamespaceは追加フラグが必要、TSXは非対応
  • 型インポートにはtypeキーワードが必須
  • スクリプト実行やプロトタイピングには最適、本番適用は慎重に

参考リンク

Careerバナーconsultingバナー