使用mongoose-paginate-ts时的分页类型定义与导入报错问题
编辑修正:
我在最初的帖子中遗漏了一点:我之前从全局文件导出mongoose-paginate-ts的函数和接口,然后在各schema文件中导入使用。但看起来我需要在每个schema文件中直接导入该模块才能正常工作,来自CommonJS类型node_module的接口无法在文件间导出和导入(目前不确定这是否是正确原因)
我在使用mongoose-paginate-ts模块时遇到了ESM导入兼容问题。
模块官方给出的使用示例如下:
import { mongoosePagination, Pagination } from "mongoose-paginate-ts"; type User = mongoose.Document & { username: String, accounts: [mongoose.Types.ObjectId] }; const userSchema = new Schema({ username: String, accounts: [{ type: ObjectId, ref: "Account" }] }); userSchema.plugin(mongoosePagination); const User: Pagination<User> = mongoose.model<User, Pagination<User>>("User", userSchema); //User.paginate()
代码构建过程没有问题,但执行以下开发启动命令时出现报错:
nodemon --ext 'ts,js,cjs,json' --ignore 'tests/' --exec 'ts-node-esm src/index.ts'
报错信息:
import { mongoosePagination, Pagination } from "mongoose-paginate-ts"; ^^^^^^^^^^ SyntaxError: Named export 'Pagination' not found. The requested module 'mongoose-paginate-ts' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using: import pkg from 'mongoose-paginate-ts'; const { mongoosePagination, Pagination } = pkg; at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21) at async ModuleJob.run (node:internal/modules/esm/module_job:190:5)
我的tsconfig.json配置:
{ "compilerOptions": { "experimentalDecorators": true, "target": "ESNext", "module": "ESNext", "rootDir": "./src", "moduleResolution": "NodeNext", "baseUrl": "./src", "outDir": "build", "types": ["node", "mocha"], "allowJs": true, "checkJs": false, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": false, "skipLibCheck": true, "resolveJsonModule": true }, "ts-node": { "swc": true }, "exclude": ["tests", "node_modules"] }
按照报错提示尝试默认导入后解构,却发现找不到Pagination接口:
import pkg from 'mongoose-paginate-ts'; const { mongoosePagination, Pagination } = pkg; // Pagination 未找到
针对CommonJS模块在ESM环境下的导入兼容问题,以及类型接口无法解构的情况,可以尝试以下几种方案:
方案1:分离运行时代码与类型导入
Pagination是TypeScript类型接口,仅在编译阶段生效,不会被打包到运行时JS中。可以用类型导入语法单独获取:
// 导入运行时函数 import mongoosePaginateTs from 'mongoose-paginate-ts'; const { mongoosePagination } = mongoosePaginateTs; // 单独导入类型(仅编译阶段识别) import type { Pagination } from 'mongoose-paginate-ts';
这种方式既符合ESM导入规范,又能正确获取类型,避免运行时解构错误。
方案2:调整模块解析配置
尝试将tsconfig.json中的moduleResolution改为Node,同时确保allowSyntheticDefaultImports开启:
{ "compilerOptions": { // ...其他配置 "moduleResolution": "Node", "allowSyntheticDefaultImports": true } }
部分CommonJS模块在NodeNext解析模式下会出现类型导出识别异常,切换到传统Node模式可能解决问题。
方案3:临时使用require导入
如果以上方案无效,可暂时用CommonJS的require语法导入运行时代码,配合类型导入获取接口:
const mongoosePaginateTs = require('mongoose-paginate-ts'); const { mongoosePagination } = mongoosePaginateTs; import type { Pagination } from 'mongoose-paginate-ts'; // 类型使用保持不变 const User: Pagination<User> = mongoose.model<User, Pagination<User>>("User", userSchema);
另外针对你提到的全局导出后跨文件无法使用的问题:由于CommonJS模块的类型导出在ESM环境下跨文件传递存在兼容性问题,建议在每个需要使用的schema文件中直接导入模块和类型,避免通过中间文件中转导出,减少类型解析异常。
内容的提问来源于stack exchange,提问作者Kevin Barns

