如何解决TypeScript项目中的ERR_UNKNOWN_FILE_EXTENSION错误
Node.js + TypeScript ESM 配置问题解决
我近期搭建一个使用ES6 import 语句和顶层await的Node.js项目时遇到了两个核心问题:
- 直接用
npx ts-node index.ts运行时,报错无法识别.ts扩展名:
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /home/zhyp/Code/ts-test/src/index.ts
- 添加
--esm标志用npx ts-node --esm index.ts运行时,出现模块找不到错误:
throw new ERR_MODULE_NOT_FOUND(
^
CustomError: Cannot find module '/home/zhyp/Code/ts-test/src/imported-file' imported from /home/zhyp/Code/ts-test/src/index.ts
试过给导入加.js扩展名能运行,但用.ts扩展名需要开启allowImportingTsExtensions,同时开启noEmit又会导致tsc无法构建,求解决。
问题根源
package.json中type: module的冲突:设置type: module后,Node.js默认以ESM模式处理文件,但ts-node默认是CommonJS行为,直接运行会因为Node.js不识别.ts扩展名报错。- ESM的模块解析规则:Node.js的ESM要求导入必须带完整扩展名,而TypeScript默认允许省略扩展名,ts-node在ESM模式下需额外配置才能处理TypeScript文件的扩展名解析。
allowImportingTsExtensions的局限性:开启该选项后,TypeScript允许导入.ts文件,但如果同时开启noEmit,tsc无法生成对应的.js文件,导致构建失败。
解决步骤
1. 调整tsconfig.json配置
添加ESM相关编译选项,兼顾运行与构建:
{ "compilerOptions": { "target": "es2022", "module": "es2022", "rootDir": "src", "resolveJsonModule": true, "allowJs": true, "outDir": "build", "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitAny": true, "skipLibCheck": true, // 新增ESM适配配置 "moduleResolution": "node16", // 匹配Node.js的ESM解析逻辑 "allowImportingTsExtensions": true, // 允许导入.ts扩展名 "noEmit": false, // 关闭noEmit,确保tsc能正常构建 "esModuleInterop": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
2. 更新package.json脚本
明确启动脚本使用ESM模式,添加构建命令:
{ "name": "typescript-node", "version": "1.0.0", "description": "TypeScript Template with Node.js", "main": "build/index.js", // 指向构建后的产物文件 "scripts": { "start": "nodemon --exec 'ts-node --esm' src/index.ts", "build": "tsc" // 添加正式构建脚本 }, "dependencies": { "@types/node": "14.14.29", "ts-node": "10.9.1", "typescript": "5.0.4" }, "devDependencies": { "@types/express": "^4.17.6", "nodemon": "1.18.4" }, "keywords": [], "type": "module" }
3. 调整导入语句
保持导入使用.ts扩展名(因已开启allowImportingTsExtensions):
// index.ts import test from "./imported-file.ts"; console.log(test);
4. 验证运行与构建
- 开发运行:执行
npm start,nodemon会通过ts-node的ESM模式启动项目,可正确解析.ts文件 - 生产构建:执行
npm run build,tsc会将源码编译到build目录,生成.js文件,直接用node build/index.js即可运行构建后的项目
补充优化
如果不想在导入中写.ts扩展名,可在tsconfig.json中添加"resolvePackageJsonExports": true和"resolvePackageJsonImports": true,同时保持moduleResolution为node16或nodenext,ts-node会自动省略扩展名的TypeScript文件。
内容的提问来源于stack exchange,提问作者zhyp
相关产品推荐
相关产品推荐

