Error [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]

ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX の直し方(Node が enum を実行できない)

FIX SUMMARY verified
Applies when
node:24.18.0-alpineNode's built-in TypeScript support is strip-only; enum emits runtime code so it cannot be erased

Verified: reproduced in node:24.18.0-alpine, then the ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX signature was gone after the fix (exit 0).

node app.ts が動くようになったので TypeScript をそのまま渡したら、enum のところで止まった、というエラーです。

SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode
    at parseTypeScript (node:internal/modules/typescript:68:40)

コピペ検索用の表記ゆれです。最後の語が違うだけで、原因はどれも同じです。

  • TypeScript enum is not supported in strip-only mode
  • TypeScript namespace declaration is not supported in strip-only mode
  • TypeScript parameter property is not supported in strip-only mode
  • TypeScript import equals declaration is not supported in strip-only mode

Node は TypeScript を「消す」だけで、「変換」はしません。 enum が拒否されるのも、何を書けば動くのかも、この 1 点から決まります。

Node の TypeScript サポートは「型を消す」だけ

Node が .ts を実行できるのは、型注釈を削り落として JavaScript として動かしているからです。この動作を Node は strip-only mode(消すだけのモード)と呼びます。エラーメッセージにもその名前が出ています。

型注釈は消せます。消したあとに残る JavaScript は、元と同じ意味です。

function label(s: string): string {   // : string を消すだけ
  return s;
}

enum は消せません。 enum は型ではなく、実行時にオブジェクトを作る構文だからです。

enum Status {
  Active = "active",
}

これを消してしまうと、Status.Active を参照するコードが動きません。かといって Node は、enum を等価な JavaScript に組み立て直すこと(変換)はしません。だから受け取りを拒否します。

同じ理由で通らない構文

enum だけが特別なわけではありません。実行時のコードを生む TypeScript 構文は、どれも同じエラーになります。

構文実行時に何を生むかstrip-only
enumオブジェクト通らない
const enum参照先の値(インライン化する変換が要る)通らない
値を含む namespaceexport const など)即時実行関数通らない
パラメータプロパティ constructor(private x: string)代入文通らない
import fs = require("node:fs")require 呼び出し通らない
型だけの namespace / declare namespace何も生まない(消せる)通る
type / interface / as / satisfies / declare何も生まない(消せる)通る

消せるものは通り、生むものは通りません。

namespace が表の両側に出てくるのは、この線のせいです。namespace N { export const x = 1 } は実行時にオブジェクトを組み立てるので通りませんが、namespace N { export type A = string } のように型しか入っていない namespace は消せるので通りますdeclare namespace も同じです)。「namespace は使えない」ではなく、「値を書いた namespace は使えない」です。

直し方 1:消せる構文で書き直す(推奨)

enum の使い勝手は、as const のオブジェクトと、その値のユニオン型で再現できます。フラグは要りません。

// Before(ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX になる)
enum Status {
  Active = "active",
  Archived = "archived",
}

function label(s: Status): string {
  return `status=${s}`;
}

console.log(label(Status.Active));
// After(既定の Node でそのまま動く)
const Status = {
  Active: "active",
  Archived: "archived",
} as const;

type Status = (typeof Status)[keyof typeof Status];

function label(s: Status): string {
  return `status=${s}`;
}

console.log(label(Status.Active));

Status.Active という呼び出し方も、Status を型として使うことも、そのまま残ります。値は素の JavaScript のオブジェクト、型は型注釈なので、どちらも消せる側に収まります

直し方 2:--experimental-transform-types(Node 26 で削除)

enum を残したまま動かすフラグが、かつてありました。

node --experimental-transform-types app.ts

変換モードを明示的に有効にする指定で、これなら enum は等価な JavaScript に組み立て直されて動きます。

ただし、このフラグは Node 26 で削除されました。

$ node --experimental-transform-types app.ts
node: bad option: --experimental-transform-types

使える版は限られます。

Node--experimental-transform-types
22.7.0 〜 25.x使える
26 以降存在しないbad option で起動しない)

代わりのフラグは用意されていません。Node 26 以降で残るのは、直し方 1(消せる構文へ書き直す)か、tsc などでビルドしてから .js を実行する従来の方式の 2 つだけになります。

名前の似たフラグに注意

node --experimental-strip-types app.ts   # enum は通りません

--experimental-strip-types消すだけのモードを有効にするフラグで、enum は通りません。付けてもまったく同じエラーが出ます。「実験的フラグを付ければ動くはず」と考えてこちらを付けると、何も変わらないまま行き詰まります。

紛らわしいのは、このフラグの意味が版によって変わることです。

  • 22.6.0 〜 22.17.x / 23.0 〜 23.5.x:型ストリッピングがまだ既定ではないので、このフラグが .ts を実行するために必要です。付けなければ ERR_UNKNOWN_FILE_EXTENSION で止まります。
  • 22.18.0 以降 / 23.6.0 以降 / 24 / 26:型ストリッピングが既定なので、このフラグは既定と同じモードを明示するだけです。付けても何も変わりません。

Node 26 でも --experimental-strip-types は受け付けられます(bad option にはなりません)。削除されたのは transform のほうだけです。

型チェックは通ります

tscenum を何とも思いません。 型チェックは通り、エラーは実行時にだけ出ます。

$ npx tsc --noEmit app.ts
(何も出ない。エラー無し)

enum は正しい TypeScript です。型チェッカから見て、問題は 1 つもありません。CI の型検査は緑のまま通り、node app.ts の実行だけが落ちます。

このズレは、TypeScript 5.8 以降の erasableSyntaxOnly で埋められます。**「消せない構文を書いたら型検査で落とす」**という指定です。

// tsconfig.json
{
  "compilerOptions": {
    "erasableSyntaxOnly": true
  }
}

これを入れると、enum は型検査の時点で弾かれます。

app.ts(1,6): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.

Node で実行する前に、エディタと CI が教えてくれるようになります。node.ts を直接動かす方針なら、入れておく価値があります。

切り分け

  • --experimental-strip-types を付けたのに何も変わらない → 型ストリッピングが既定の版(22.18.0 以降)では、そのフラグは既定と同じモードを明示するだけです。enum は通りません。書き直してください(Node 26 では --experimental-transform-types も使えません)。
  • エラーが ERR_UNKNOWN_FILE_EXTENSION: ".ts" → こちらは .ts をそもそも実行できていません。Node の版が古いか、型ストリッピングが有効になっていない状態です。ERR_UNKNOWN_FILE_EXTENSION: “.ts” の直し方 を参照してください。このエラー(ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX)は、.ts の実行自体には成功していて、中の構文で止まっているという一段先の状態です。
  • enum を消したのに、まだ同じエラーが出る → メッセージの最後の語を読んでください。namespace declarationparameter property なら、別の場所で同じ制限に当たっています。上の表で該当する構文を探してください。
  • エラーが ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX ではなく、ただの SyntaxError: Invalid or unexpected token で、^@ の行を指している → それは decorator です。この記事の変換フラグでは直りません(decorator は変換されない別の境界です)。SyntaxError: Invalid or unexpected token の直し方(decorator) を参照してください。
  • 依存ライブラリの .ts で落ちている → それは別のエラーです(ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING)。node_modules の中の .ts は構文を見る前に弾かれるので、そもそもこのエラーにはなりません。フラグでは外せません。 node_modules の中の .ts は実行されない を参照してください。
  • tsx では動いていたtsx は変換まで行うので enum も動きます。Node の組み込みサポートは変換しないので、同じコードでも動く/動かないが分かれます

検証環境

  • node:24.18.0-alpine、ネットワーク無し
  • 再現:enum を含む .tsnode reproduce/app.ts で実行し、ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX が出て終了コード 1
  • 修正:同じ処理を as const のオブジェクトとユニオン型で書き直すだけで終了コード 0・シグネチャ消滅。フラグは付けていません。出力(status=active)も再現側と同じです
  • 通らない構文(enum / const enum / 値を含む namespace / パラメータプロパティ / import x = require())と、通る構文(型だけの namespace / declare namespace / type / interface / as / satisfies / declare)は、それぞれ個別のファイルを node:24.18.0-alpine で実行して確認しました
  • --experimental-transform-typesenum が動く(22.18.0 / 24.18.0 / 25.9.0)」「Node 26.5.0 では bad option になり、フラグ自体が存在しない」「--experimental-strip-types は Node 26 でも受け付けられるが enum は通らない」「Node 22.18.0 / 23.11.1 / 24.18.0 / 26.5.0 のいずれでも enum は通らない」「Node 22.6.0 では型注釈だけの .ts すら既定では実行できない」も、それぞれ実行して確認しています
  • tsc --noEmitenum を通す」「--erasableSyntaxOnly を付けると error TS1294 で落ちる」は、[email protected] をインストールして確認しました

tsconfig.json 経由での erasableSyntaxOnly の設定は、コマンドラインの指定と機構が同じ(型検査時に消せない構文を弾く)ことを根拠にした対処であり、tsconfig.json からの再現は通していません。ts-node / tsx / esbuild での挙動も確認していません。

検証(machine-verified)

この修正は node:24.18.0-alpine のバージョン固定コンテナ内で再現し、修正後に ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX のシグネチャが消えることを機械で確認しています。

verify — run-case.mjs
$ node run-case.mjs node/unsupported-typescript-syntax-enum
● reproduce ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX present ✓
● apply fix exit 0
● re-run ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX gone ✓
PASS verified · node:24.18.0-alpine · signature gone