TypeScript编译后Node运行报错Cannot find module,该如何解决?
这个问题的核心是Node.js ES模块的路径要求和TypeScript默认编译行为不匹配导致的:
- Node.js 要求ES模块的相对导入必须带有完整文件扩展名(比如
.js),否则会报错找不到模块; - TypeScript 默认编译时,不会自动给导入路径添加
.js后缀,所以编译后的dist/server.js里的导入还是./db/mongodb-client,不带扩展名,Node自然找不到对应的.js文件。
下面是几种可行的解决方案:
方案1:配置TypeScript使用NodeNext/Node16模块解析(推荐)
修改你的tsconfig.json,设置module和moduleResolution为NodeNext或Node16,让TypeScript的模块解析规则和Node.js ES模块对齐:
{ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "./dist", "target": "ES2020", // 需指定支持ES模块的目标版本,至少ES2020 "strict": true // 可选,开启严格模式 }, "include": ["*.ts", "db/**/*.ts"] // 根据你的源码路径调整 }
配置完成后,你在server.ts里依然可以写:
import db from "./db/mongodb-client";
TypeScript会自动在编译后的dist/server.js里把路径补全为./db/mongodb-client.js,完全符合Node.js的要求,运行node dist/server.js就不会报错了。
方案2:在TypeScript源码中保留.js后缀(官方允许的写法)
虽然看起来有点违和,但TypeScript官方是支持在ES模块场景下,源码里导入时加上.js后缀的——TypeScript会自动映射到对应的.ts文件进行编译,最终生成的JS文件里的路径就是正确的.js后缀,能被Node正常识别。
这种写法不需要额外配置,适合不想调整tsconfig的场景,比如你的导入可以写成:
import db from "./db/mongodb-client.js";
方案3:使用CommonJS模块(不推荐,除非兼容旧项目)
如果你的项目可以改用CommonJS模块,修改tsconfig.json的module为CommonJS:
{ "compilerOptions": { "module": "CommonJS", "outDir": "./dist", "target": "ES2015" } }
此时编译后的JS会用require()语法,Node.js对CommonJS的路径不强制要求扩展名,所以import db from "./db/mongodb-client";编译后能正常运行。但CommonJS是旧的模块系统,不推荐新项目使用。
总结:优先选择方案1,既能保持TypeScript源码的写法习惯,又能完美适配Node.js的ES模块规则。
内容的提问来源于stack exchange,提问作者Nausika

