node.js - Node 16を使用している場合、TypeScriptに ".js" 拡張子を付けてエクスポート/インポートを生成させるには?
ESMモジュールを使用するTS 4.7のライブラリを持っています。
tsconfig.json:
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020"],
"moduleResolution": "node",
package.json
"type": "module",
私は一つのくだらないエクスポートしかないメインファイルを持っています:
index.ts
export { Spig } from './spig';
次のようにコンパイルされます:
index.js
export { Spig } from './spig';
//# sourceMappingURL=index.js.map
問題
このライブラリを Node CLI プログラム(ESM モジュールも有効にした状態)から使用すると、次のエラーが発生します:
Cannot find module <path>/lib/spig imported from <path>/lib/index.js
生成された index.js に .js を 手動で追加すると、問題は解消されます:
export { Spig } from './spig.js';
TypeScriptコンパイラに拡張子も生成させるにはどうすればいいですか?ここで何を見落としているのでしょうか?
回答 #1
ESMモジュールのインポートでは、もはやファイル拡張子を省略できません。拡張子は常に .js や .jsx である必要があり、TypeScriptファイルに対して .ts や .tsx は使用できません。したがって、index.ts では、ESMモジュールを使用する場合、以下のように spig のエクスポートや他のインポート/エクスポートされるすべてのファイルに拡張子を追加する必要があります。
index.ts
export { Spig } from './spig.js';
また、ESMモジュールが期待通りに動作するように、moduleResolution は Node16 または NodeNext に設定する必要があります。
ドキュメントに記載されているように(強調は私によるものです):
相対インポートパスには完全な拡張子が必要です(例:import "./foo" の代わりに import "./foo.js" と書く必要があります)。
.tsファイルがESモジュールとしてコンパイルされると、.js出力ではECMAScriptのimport/export構文はそのまま維持されます。CommonJSモジュールとしてコンパイルされる場合は、module: commonjsの下で今日得られるのと同じ出力が生成されます。
これはまた、パスがESモジュールである.tsファイルとCJSモジュールであるファイルの間で異なる方法で解決されることを意味します。例えば、今日次のコードがあるとしましょう:
// ./foo.ts
export function helper() {
// ...
}
// ./bar.ts
import { helper } from "./foo"; // only works in CJS
helper();
このコードはCommonJSモジュールでは動作しますが、ESモジュールでは失敗します。なぜなら、相対インポートパスには拡張子を使用する必要があるからです。その結果、foo.tsの出力の拡張子を使用するように書き直す必要があります。つまり、bar.tsは代わりに./foo.jsからインポートする必要があります。
// ./bar.ts
import { helper } from "./foo.js"; // works in ESM & CJS
helper();
最初は少し面倒に感じるかもしれませんが、オートインポートやパス補完のようなTypeScriptのツールは、通常これを自動で行ってくれます。
