Node.js+TypeScript+ts-node搭建ESM项目遇.ts扩展名错误
问题描述
我要搭建一个基于Node.js、TypeScript、ts-node的ESM模块项目,因为部分NPM库最新版本要求ESM,所以需要把TypeScript代码编译成ESM而非CommonJS。但运行index.js时一直报错:TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for SomeClass.ts。
相关代码如下:
index.js
import TsNode from "ts-node"; const tsNodeService = TsNode.register({ transpileOnly: false }); TsNode.createEsmHooks(tsNodeService); //试过添加和移除该行 (async () => { const SomeClass = await import("./SomeClass.ts"); console.log(new SomeClass().method("abc", 123)); })(); // 也尝试过以下写法: /* import SomeClass from "./SomeClass.ts"; console.log(new SomeClass().method("abc", 123)); */
SomeClass.ts
export default class SomeClass { method(a: string, b: number) { return `${a} and ${b}`; } }
tsconfig.json
{ "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "baseUrl": "./", "outDir": "./output/", "module": "Node16", "target": "ES2022", "strict": true, "strictPropertyInitialization": false, "esModuleInterop": true, "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, "sourceMap": true, "pretty": true, "experimentalDecorators": true, "allowJs": true, "resolveJsonModule": true }, "exclude": [ "node_modules/**/*" ] }
package.json
{ "name": "testesmts", "version": "1.0.0", "description": "", "main": "index.js", "author": "", "type": "module", "license": "ISC", "dependencies": { "ts-node": "^10.9.1", "typescript": "^4.9.3" } }
解决方案
以下是解决该问题的关键步骤:
调整package.json配置,添加启动脚本
保留type: "module",新增ts-node的ESM启动脚本,无需手动注册ts-node:{ "name": "testesmts", "version": "1.0.0", "type": "module", "scripts": { "start": "ts-node --esm ./index.ts" }, "dependencies": { "ts-node": "^10.9.1", "typescript": "^4.9.3" } }完善tsconfig.json的ESM解析配置
确保moduleResolution与module一致,启用Node16的ESM解析规则:{ "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "baseUrl": "./", "outDir": "./output/", "module": "Node16", "target": "ES2022", "moduleResolution": "Node16", // 必须配置此项,匹配Node16的模块解析逻辑 "strict": true, "strictPropertyInitialization": false, "esModuleInterop": true, "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, "sourceMap": true, "experimentalDecorators": true, "allowJs": true, "resolveJsonModule": true, "skipLibCheck": true }, "exclude": ["node_modules/**/*"] }将入口文件改为TS格式,简化代码
删除原index.js,创建index.ts作为入口,避免手动注册ts-node的复杂操作:// 静态导入写法 import SomeClass from "./SomeClass.ts"; console.log(new SomeClass().method("abc", 123)); // 或动态导入写法(需解构default导出) /* (async () => { const { default: SomeClass } = await import("./SomeClass.ts"); console.log(new SomeClass().method("abc", 123)); })(); */用正确命令启动项目
执行npm start,或直接运行:ts-node --esm ./index.ts不要直接运行index.js,因为ESM模式下Node.js无法自动识别.ts文件扩展名,必须由ts-node处理。
移除多余的手动注册代码
原index.js中的TsNode.register和createEsmHooks代码完全不需要,ts-node --esm参数会自动处理ESM环境下的TS文件解析、转译逻辑。
内容的提问来源于stack exchange,提问作者Sonaht
相关产品推荐
相关产品推荐

