できない.dev

Node.js で「ERR_UNKNOWN_FILE_EXTENSION: Unknown file extension ".ts"」が解決できない

古い Node で .ts を直接実行すると拡張子を解釈できずこのエラーになる。tsx などのランナーで実行するか、型除去が既定の新しい Node(v22.18 / v23.6 以降)にする。

公開: 更新:

実行例あり(2026-08-28 に実環境で検証)

要約

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" は、Node.js が .ts ファイルをどう扱えばよいか分からないときに出ます。
Node はもともと JavaScript の実行環境で、TypeScript をそのまま動かす仕組みは新しいバージョンで段階的に入りました。
古い Node で node app.ts を実行するとこのエラーになります。
最も確実なのは tsx などのランナーを使うことです。
新しい Node なら型を取り除いて直接実行できます。

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /path/to/app.ts

実行例

node:20(v20.20.2)で .ts をそのまま渡すと、拡張子を解決できない ERR_UNKNOWN_FILE_EXTENSION が投げられて終了コード 1 で止まる。
tsx を挟んだ場合と、tsc で dist/app.js へ変換してから実行した場合は、どちらも同じ hello from ts を出して 0 で終わる。

$ node --version
v20.20.2
$ node app.ts
node:internal/modules/esm/get_format:189
  throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath);
        ^
 
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /tmp/tmp.PWGxfYuxWo/app.ts
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:189:9)
    at defaultGetFormat (node:internal/modules/esm/get_format:232:36)
    at defaultLoad (node:internal/modules/esm/load:145:22)
    at async ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:543:45)
    at async ModuleJob._link (node:internal/modules/esm/module_job:148:19) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
 
Node.js v20.20.2
$ echo $?
1
$ npx tsx app.ts
hello from ts
$ echo $?
0
$ npx tsc app.ts --module nodenext --outDir dist
$ node dist/app.js
hello from ts
$ echo $?
0

— 2026-08-28 時点の出力

検証環境

検証日
実行環境
node:20Debian GNU/Linux 12 (bookworm)
バージョン
  • Node.js 20.20.2
  • npm 10.8.2
  • Python 3.11.2
  • Git 2.39.5

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

よくある原因

  1. TypeScript を直接実行: node app.ts のように、JavaScript への変換やランナーを介さず実行している。
  2. Node のバージョンが古い: 型除去(type stripping)に未対応の Node を使っている。
  3. ローダー未指定: ESM 環境で .ts を解釈するローダー/ランナーを指定していない。
  4. ts-node の ESM 設定不整合: "type": "module" 環境で loader の指定が噛み合っていない。

解決策

1. tsx で実行する(バージョン非依存で確実)

tsx は TypeScript をそのまま実行できるランナーです。
Node のバージョンに関係なく動くため、手っ取り早く確実です。

npx tsx app.ts

2. 新しい Node の型除去を使う

公式ドキュメントによると、Node.js は v23.6.0 / v22.18.0 以降、消去可能な TypeScript 構文を含むファイルを既定で実行できます(型は除去されるだけで型チェックは行われません)。
これらのバージョンに更新すれば、追加ツール無しで動きます。

node --version   # v23.6.0 / v22.18.0 以降かを確認
node app.ts

v22.6.0 から v22.17 など型除去が既定で無効な系列では、フラグを付けて有効化します。

node --experimental-strip-types app.ts

なお enum や実行コードを伴う namespace のように変換が必要な構文は、型除去だけでは動かず ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX になります。
その場合は tsx や事前コンパイルを使います。

3. 事前に tsc でコンパイルする

ビルド成果物を Node で動かす構成なら、tsc で JavaScript に変換してから生成物を実行します。
本番ではこの形が無難です。

npx tsc
node dist/app.js

この記事は役立ちましたか?