You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript分文件声明Mongoose模型重复声明报错解决方案

Node.js TypeScript 项目 Mongoose 模型重复声明报错问题

项目背景

项目核心模型存放在mongoModels目录,目前共定义2个存在关联关系的Mongo模型:

  • Category 模型包含expertUserIds字段,存储由 User 模型_id组成的关联数组
  • 项目目录结构参考:
    项目目录结构截图

现有两个模型的原代码如下:

user.ts 原代码

const { Schema, model } = require("mongoose");

const userSchema = new Schema({
  username: {
    type: String,
    require: true,
  },
  password: {
    type: String,
    require: true,
  },
});

module.exports = model("User", userSchema);

category.ts 原代码

const { Schema, model } = require("mongoose");

const categorySchema = new Schema({
  name: {
    type: String,
    require: true,
  },
  description: {
    type: String,
  },
  expertUserIds: [
    {
      type: Schema.Types.ObjectId,
      ref: "User",
    },
  ],
});

module.exports = model("Category", categorySchema);

相同逻辑的代码在原生JavaScript项目中可正常运行,但在TypeScript环境下抛出如下错误:

mongoModels/category.ts:1:17 - error TS2451: Cannot redeclare block-scoped variable 'model'.
1 const { Schema, model } = require("mongoose");

两个模型文件中解构引入的Schema、model变量均存在同类报错,TypeScript判定该声明语句已在其他文件中定义,不允许重复声明。


错误产生原因

TypeScript 对文件的模块判定规则和 Node.js 原生 CommonJS 逻辑存在差异:

  1. 如果一个.ts文件顶层没有出现ESM规范的import/export关键字,TypeScript 会默认将该文件识别为全局脚本文件,所有顶层声明的变量都会被挂载到全局作用域,而非文件独立作用域。
  2. 原代码使用 CommonJS 规范的require()和module.exports,没有ESM风格的导入导出标记,因此TS把user.ts和category.ts都当成了全局脚本,两个文件顶层声明的Schema、model常量都被放到全局作用域,同名const变量重复声明自然触发TS2451错误。
  3. 原生JS环境下,Node.js 会自动将每个CommonJS文件包裹在独立的模块函数中,天然实现文件级作用域隔离,因此不会出现该问题。

修复方案

可任选以下一种方案修复,推荐优先使用前两种:

  • 最小改动方案:在两个模型文件的最顶部添加一行空导出语句,强制TS将文件识别为独立模块,无需修改原有业务逻辑:
    export {};
    // 原有代码保持不变
    const { Schema, model } = require("mongoose");
    // ... 剩余原有代码
    
  • TS规范推荐方案:将CommonJS风格的引入、导出改写为TS原生支持的ESM写法,从根源上让TS识别模块边界,改写后的参考代码如下:
    改写后user.ts:
    import { Schema, model } from "mongoose";
    
    const userSchema = new Schema({
      username: {
        type: String,
        required: true, // 注:原代码写的require为mongoose配置笔误,正确校验属性名为required
      },
      password: {
        type: String,
        required: true,
      },
    });
    
    export default model("User", userSchema);
    
    改写后category.ts:
    import { Schema, model } from "mongoose";
    
    const categorySchema = new Schema({
      name: {
        type: String,
        required: true,
      },
      description: {
        type: String,
      },
      expertUserIds: [
        {
          type: Schema.Types.ObjectId,
          ref: "User",
        },
      ],
    });
    
    export default model("Category", categorySchema);
    
  • 配置兼容方案:修改项目根目录的tsconfig.json,确认配置中compilerOptions.module设置为CommonJS、compilerOptions.moduleResolution设置为node,让TS适配Node.js的CommonJS模块解析规则,不过该方案兼容性不如前两种稳定。

内容的提问来源于stack exchange,提问作者Borislav Stefanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:54:30