Node.js 26で消えた–experimental-transform-typesと、ERR_UNSUPPORTED_TYPESCRIPT_SYNTAXで落ちるenumの書き換え方を、v26.8.2での実行結果とともに示します。
この記事が解決する悩み
- Node.js 26 に上げたら、それまで動いていた
.tsがERR_UNSUPPORTED_TYPESCRIPT_SYNTAXで落ちるようになった - 回避策として使っていた
--experimental-transform-typesが「bad option」で起動すらしない - どの構文がダメなのか、どう書き換えればいいのか分からない
対象読者: Node.js から .ts を直接実行している人(ビルドスクリプト、CLI ツール、小さなバッチなど)
前提知識: Node.js 22 以降の型ストリッピング、TypeScript の基本的な構文
結論
Node.js のネイティブ TypeScript 対応は「型を空白に置き換えるだけ」です。JavaScript のコードを新しく生成する必要がある構文は、そもそも実行できません。対象になるのは enum、ランタイムコードを含む namespace、コンストラクタのパラメータプロパティ、import エイリアスの4つですね。
そして Node.js 26(v26.0.0)で --experimental-transform-types が削除されました。以前はこのフラグを付ければ変換までやってくれたのですが、いまは bad option で起動しません。残された道は「構文を書き換える」「tsc で先に変換する」「tsx などに任せる」の3つですね。
いちばん手っ取り早いのは enum を as const オブジェクトに置き換える方法です。
// fixed.ts
const Color = {
Red: "red",
Blue: "blue",
} as const;
type Color = (typeof Color)[keyof typeof Color];
function paint(color: Color) {
console.log("paint:", color);
}
paint(Color.Red);
実行結果です。
$ node fixed.ts
paint: red
型は typeof で引き継げるので、呼び出し側のコードはそのまま使えます。この書き換えだけで大半のプロジェクトは通りますよ。
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX とは — どの Node.js バージョンで出るのか
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX は、Node.js の型ストリッピング(strip-only モード)が「型を消すだけでは実行できない構文」に当たったときに返すエラーコードです。メッセージは次の形で、後半にどの構文が原因かが入ります。
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode
バージョンの条件は、2つに分けて考えると整理しやすいですね。
- エラー自体は Node.js 26 で新しく出たものではない。 型ストリッピングは Node.js 22 以降の機能で、変換が必要な構文を
.tsに書いて strip-only モードで実行すれば同じコードが返ります。つまり 26 未満でも起きます。 - Node.js 26(v26.0.0)で変わったのは、回避フラグのほう。 以前は
--experimental-transform-typesを付ければ変換までやってくれたので、このエラーを避けられていました。26 でそのフラグが削除されたためbad option: --experimental-transform-typesで起動すらしなくなり、構文を書き換える以外に道がなくなりました。
「26 に上げたら急に落ちるようになった」という症状の正体は、エラーが新設されたのではなく、それまで黙って変換してくれていた逃げ道が消えたことです。
エラーの再現手順
まず手元で再現させます。ホスト環境を汚さないように、公式のポータブル配布を一時ディレクトリに展開して使います。
$ python -c "import urllib.request,zipfile;urllib.request.urlretrieve('https://nodejs.org/dist/v26.8.2/node-v26.8.2-win-x64.zip','node.zip');zipfile.ZipFile('node.zip').extractall('.')"
$ ./node-v26.8.2-win-x64/node.exe --version
v26.8.2
落ちる構文を4つ用意します。ES Modules として動かすので、package.json に "type": "module" を入れておきます。
// enum.ts
enum Color {
Red = "red",
Blue = "blue",
}
console.log(Color.Red);
// ns.ts
namespace Counter {
export let count = 0;
export function inc() {
count += 1;
}
}
Counter.inc();
console.log(Counter.count);
// param.ts
class User {
constructor(private name: string, public age: number) {}
greet() {
return `${this.name} (${this.age})`;
}
}
console.log(new User("taro", 30).greet());
// alias.ts
import path = require("node:path");
console.log(path.basename("/tmp/a.ts"));
順番に実行すると、こうなります。
$ node enum.ts
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode
$ node ns.ts
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript namespace declaration is not supported in strip-only mode
$ node param.ts
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript parameter property is not supported in strip-only mode
$ node alias.ts
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript import equals declaration is not supported in strip-only mode
すべて exit code 1 で落ちます。4つとも同じエラーコードですが、メッセージの後半に原因が出ているので、どの構文が引っかかっているかはその1行で特定できますね。
なぜ「型を消すだけ」だと落ちるのか
Node.js の型ストリッピングは、TypeScript の型まわりの記述を空白に置き換えるだけの仕組みです。型チェックはしませんし、ソースマップも作りません。行番号がずれないのは、行を消さずに空白で埋めているからです。
引っかかるのは、enum やランタイムコード付きの namespace が「型」ではなく「値」を生み出す構文だという点ですね。enum は実行時にオブジェクトを作る必要があります。パラメータプロパティは this.name = name を暗黙で生やします。これを実現するには JavaScript コードの生成が必要で、空白に置き換えるだけの仕組みでは無理があります。
型だけの namespace は消せるので通ります。実際に確認したのがこちらです。
// erasable.ts
namespace TypeOnly {
export type A = string;
}
const value: TypeOnly.A = "erasable syntax only";
const config = { retries: 3 } satisfies { retries: number };
console.log(value, config.retries);
$ node erasable.ts
erasable syntax only 3
消せる構文かどうかが分かれ目です。satisfies や型注釈、型だけの namespace は問題ありません。
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX の直し方(構文別)
enum → as const オブジェクト
先ほどの書き換えが基本形です。値を列挙して型を導出するので、分岐の網羅チェックも効きます。
const Status = {
Pending: "pending",
Done: "done",
} as const;
type Status = (typeof Status)[keyof typeof Status];
function label(status: Status) {
if (status === Status.Pending) {
return "処理中";
}
return "完了";
}
console.log(label(Status.Done));
namespace → ただのオブジェクトかモジュール
値をまとめたいだけなら、オブジェクトか別ファイルのモジュールにすれば十分です。
// counter.ts
let count = 0;
export function inc() {
count += 1;
}
export function current() {
return count;
}
パラメータプロパティ → 明示的に代入する
暗黙の代入を自分で書くだけです。行数は増えますが、挙動は同じになります。
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
return `${this.name} (${this.age})`;
}
}
console.log(new User("taro", 30).greet());
import equals → ESM の import
import path = require("node:path") は CommonJS 向けの構文です。ES Modules なら普通の import に置き換えます。
import path from "node:path";
console.log(path.basename("/tmp/a.ts"));
型だけの import には type を付ける
これは構文エラーではなく、実行時のエラーとして出ます。型に type を付けないと値の import として扱われ、存在しないエクスポートを探しに行くためです。
// mod.ts
export type Type1 = string;
export const fn = (value: Type1) => value.toUpperCase();
NG と OK を並べます。
$ node typed_import.ts
SyntaxError: The requested module './mod.ts' does not provide an export named 'Type1'
$ node typed_import_ok.ts
TYPE ONLY IMPORT
拡張子なしの import は解決できない
Node.js の ESM と同じルールで、相対 import には拡張子が必須です。パスは実行時の作業ディレクトリで、長いので省略しています。
$ node extless.ts
Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\...\helper' imported from C:\...\extless.ts
node_modules 配下の .ts は実行できない
依存パッケージが TypeScript のまま配布されている場合も、型ストリッピングは拒否します。
$ node use_pkg.ts
Error [ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING]: Stripping types is currently unsupported for files under node_modules
パッケージ作者側がビルド済みの JavaScript を配布するか、こちら側でビルドステップを挟むかのどちらかになります。
tsconfig で事前に落とす
実行してから気づくより、型チェックの時点で止めておきましょう。erasableSyntaxOnly を入れておくと、Node.js が実行できない構文を tsc が先に弾いてくれます。
{
"compilerOptions": {
"target": "esnext",
"module": "nodenext",
"strict": true,
"noEmit": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true
}
}
実際に TypeScript 6.0.2 で回した結果です。
$ npx -p typescript@6.0.2 tsc -p tsconfig.check.json
enum.ts(2,6): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
param.ts(3,15): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
param.ts(3,37): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
typed_import.ts(1,10): error TS1484: 'Type1' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
実行時に does not provide an export named で落ちる型 import も、TS1484 として事前に捕まえられます。allowImportingTsExtensions を入れておくと、拡張子付き import の TS5097 は出なくなりますよ。CI に1回入れておくと事故が減りますよ。
どうしても書き換えたくないとき
enum を大量に使っていて即時の書き換えが難しい場合は、実行側を替えるのが現実的です。tsx なら enum もパラメータプロパティも変換して実行できます。
$ npx tsx enum.ts
red
もう1つは tsc で JavaScript に変換してから node で実行する方法です。ビルド成果物を配る形になるので、本番運用ではこちらが安全ですね。
$ npx tsc --outDir dist enum.ts
$ node dist/enum.js
red
直ったかどうかを確認する
書き換えたら、同じコマンドをもう一度流して確かめます。この記事で使った確認は次の3つです。
- その場で実行する。
node fixed.tsのように書き換え後のファイルを直接実行し、SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]が出ずに期待した出力(paint: redなど)が返れば解消です。型だけの namespace を試したnode erasable.tsも同じ見方で構いません。 - tsc で一括チェックする。
erasableSyntaxOnlyを入れたtsconfig.check.jsonをnpx -p typescript@6.0.2 tsc -p tsconfig.check.jsonで回し、TS1294 / TS1484 が消えていることを確認します。実行する前に落ちる箇所を洗い出せるので、CI に入れるならこちらが本命ですね。 - フラグで逃げていないかを見る。
--experimental-transform-typesを足して直ったつもりになっていないか、起動オプションを確認してください。26 ではbad optionで落ちるので、そもそも起動しません。
「実行は通るのに別のエラーが出る」場合は、原因が構文ではなくモジュール解決側に移っています。そのときは ERR_MODULE_NOT_FOUND(拡張子なしの import)や ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING(node_modules 配下の .ts)を、本文の該当箇所と照合してください。
つまずきポイント
引っかかったのはフラグまわりと、エラーの出方です。
--experimental-transform-typesはもう存在しない。 付けるとbad option: --experimental-transform-typesで即終了します。起動オプションの話なので、スタックトレースは出ません。--no-strip-typesにすると別のエラーに変わる。TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"になり、エラーの種類が変わっただけで解決はしません。--experimental-strip-typesは今も通る。 ただしストリップしかしないので、enum では同じERR_UNSUPPORTED_TYPESCRIPT_SYNTAXのままです。フラグを足せば直る話ではありません。- Node.js は tsconfig.json を読みません。
pathsや旧構文へのダウングレードは効かないので、実行時の解決は別途考える必要があります。エイリアスの解決は#始まりのサブパス import に寄せる必要があります。 - エラーの型が一定ではない。 構文の問題は
SyntaxError、モジュール解決の問題はError、拡張子の問題はTypeErrorで出ます。エラーの種類で判断しようとすると迷います。 .tsxはサポート外。 JSX を含むファイルは対象外なので、そちらは別のツールに任せることになります。
【広告】XServerドメインならドメイン取得も運用もお得。![]()
実測メモ: erasableSyntaxOnly を入れて TypeScript 6.0.2 で型チェックしたところ、enum とパラメータプロパティは TS1294、型だけの import は TS1484 で落ちました。同じ tsconfig に allowImportingTsExtensions を足すと、拡張子付き import の TS5097 は出なくなります。逆に import equals を使っているファイルを対象に含めると、TS1294 に加えてTS2591(Cannot find name 'node:path'、@types/node 未導入のため)も一緒に出ました。エラーの件数だけを見て判断せず、メッセージの種類まで確認しておきましょう。
まとめ
Node.js 26 のエラーは、型ストリッピングが「消せる構文だけ」を対象にしていることと、--experimental-transform-types が削除されたことの合わせ技です。2026年9月時点で、対応は3択に整理できます。
| 構文 | Node.js 26 の挙動 | 書き換え先 |
|---|---|---|
| enum | ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX | as const オブジェクト + typeof |
| namespace(値あり) | ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX | オブジェクト / 別モジュール |
| パラメータプロパティ | ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX | 明示的な this 代入 |
| import equals | ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX | ESM の import |
| 型だけの import | 実行時エラー | type キーワードを付ける |
| 拡張子なし import | ERR_MODULE_NOT_FOUND | .ts を明記 |
| node_modules 内の .ts | ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING | 配布側でビルドする |
いきなり全ファイルを書き換えるのが難しければ、まず tsconfig.json に erasableSyntaxOnly を入れて、対象ファイルを洗い出すのがおすすめです。落ちる箇所が一覧で出るので、作業量が見えます。そのうえで CI に tsc を挟めば、同じエラーで本番が止まることはなくなりますよ。
検証環境
| OS | Windows 11 (build 10.0.26200) |
|---|---|
| CPU | AMD Ryzen 9 PRO 8945HS w/ Radeon 780M Graphics |
| メモリ | 28GB |
| 言語/ツール | Node.js 26.8.2(公式のポータブル配布を一時ディレクトリに展開) / TypeScript 6.0.2(npx経由で型チェックのみ) / tsx 4.23.13(npx経由) |
| 使用コマンド | node enum.ts(再現)/ node fixed.ts(書き換え後)/ npx -p typescript@6.0.2 tsc -p tsconfig.check.json |
| 測定日 | 2026-09-17 |
上記の環境で実際に実行して確認した結果です。環境が異なる場合は挙動が変わることがあります。

参考
本文の記述は以下の一次情報を確認して書いています。
- Node.js 公式ドキュメント — Modules: TypeScript(型ストリッピングの仕様と対応構文)
- Node.js 公式リリースノート — v26.0.0(remove
--experimental-transform-types) - nodejs/node PR #61803 — module: remove
--experimental-transform-types - TypeScript 公式 tsconfig リファレンス — erasableSyntaxOnly
- Node.js 公式 CLI ドキュメント —
--experimental-strip-types/--no-strip-types - GitHub — privatenumber/tsx(TypeScript をそのまま実行するランナー)
あわせて読みたい
- 【pnpm】ERR_PNPM_IGNORED_BUILDS の直し方 — allowBuilds へ移行
- 【Node.js】Node 26 完全ガイド2026 — Temporal API と Iterator.concat
- 【Vite】Vite 8 移行ガイド2026 — Rolldown 統合で壊れる設定
- 【Biome】ESLint + Prettier から Biome v2 への移行ガイド2026
【広告】このサイトはConoHa WINGで運営しています。安定した高速サーバーで快適にブログを書けています。いつもありがとう!!![]()

コメント