TypeScript+discord.js报Cannot use import statement outside a module错误求助
解决方案
方案1:使用CommonJS模式(改动最小,适配性最高)
- 调整
tsconfig.json编译配置,在compilerOptions中补充以下字段:
{ "compilerOptions": { "resolveJsonModule": true, "outDir": "dist", "rootDir": "src", "module": "CommonJS", "target": "ES2021", "moduleResolution": "Node", "esModuleInterop": true, "allowSyntheticDefaultImports": true }, "extends": "@tsconfig/node16/tsconfig.json" }
- 修改动态导入逻辑,将
import()替换为CommonJS的require():
Promise.all((await getCommands("private")).map(absPath => { return { name : basename(absPath), mod: require(absPath).default as fdjsMod } })).then(modArr => { for (const { name, mod } of modArr) { publicMap.set(name.substring(0, name.length-3), mod) } })
- 修正
getCommands函数的读取逻辑:
- 生产环境运行
dist/index.js时,必须读取dist/commands目录下后缀为.js的编译后文件,不要读取src目录下的.ts源文件,Node原生无法直接解析TS语法 - 开发环境使用
ts-node运行时,再配置读取src目录下的.ts文件即可
方案2:使用ESModule模式
如果你要使用ESModule规范,按以下步骤调整:
- 在
package.json中添加"type": "module"字段 - 调整
tsconfig.json编译配置:
{ "compilerOptions": { "resolveJsonModule": true, "outDir": "dist", "rootDir": "src", "module": "NodeNext", "target": "ES2022", "moduleResolution": "NodeNext", "esModuleInterop": true, "allowSyntheticDefaultImports": true }, "extends": "@tsconfig/node16/tsconfig.json" }
- 修正所有相对导入路径,补全
.js后缀,符合ESModule的路径解析规则:
// 原写法 import * as Handler from "../../types/index" // 修正后 import * as Handler from "../../types/index.js"
- 动态导入绝对路径时,补充
file://协议前缀适配Node的ESModule解析规则:
mod: ( await import('file://' + absPath)).default as fdjsMod
通用排查步骤
- 每次修改配置后,先删除旧的
dist目录,再重新执行tsc编译,避免缓存导致的异常 - 不要直接动态导入
.ts后缀的源文件,除非你使用ts-node作为运行时 - 如开发阶段使用
ts-node运行ESModule项目,需要在tsconfig.json中补充"ts-node": {"esm": true}配置
内容的提问来源于stack exchange,提问作者Jacob Nguyen
相关产品推荐
相关产品推荐

