Mongoose与 TypeScript

前端开发 2026-07-12

TypeScript this 错误:在Mongoose静态方法中处理 timestamps +虚拟填充

Question

我正在使用 Mongoose 9.2.2TypeScript 5.9.3,并且我的schema包含:

  • timestamps: true
  • 通过 SchemaOptions.virtuals 定义的虚拟填充
  • SchemaOptions.statics 内定义的静态方法

当我调用静态方法时,TypeScript报告一个 this 上下文类型不兼容,尽管运行时代码可以正常工作。

Minimal Reproducible Example

import mongoose from 'mongoose';

const issueOneSchema = new mongoose.Schema(
  { placeholder: String },
  {
    timestamps: true,
    virtuals: {
      votes: {
        options: {
          ref: 'IssueTwo',
          localField: '_id',
          foreignField: 'issueOneId'
        }
      }
    },
    statics: {
      myStaticMethod: function () {
        console.log('placeholder');
      }
    }
  }
);

const IssueOne = mongoose.model('IssueOne', issueOneSchema);

IssueOne.myStaticMethod();

TypeScript Error

The 'this' context of type
'Model<
  { placeholder?: unknown } & DefaultTimestampProps,
  {},
  {},
  { votes: unknown } & { id: string },
  Document<
    unknown,
    {},
    { placeholder?: unknown } & DefaultTimestampProps,
    { votes: unknown } & { id: string }
  >
>'
is not assignable to method's 'this' of type
'Model<
  { placeholder?: string | null | undefined },
  {},
  {},
  { votes: unknown },
  Document<
    unknown,
    {},
    { placeholder?: string | null | undefined },
    { votes: unknown } & { id: string },
    DefaultSchemaOptions
  >
>'.
The types of 'castObject(...).placeholder' are incompatible between these types.
Type 'unknown' is not assignable to type 'string | null | undefined'.

What I Tried

  • 通过 schema.virtual() 定义虚拟填充,而不是 SchemaOptions.virtuals,就能工作。
  • 移除 timestamps: true 也能修复类型。
  • 但我想同时保留时间戳和虚拟填充,并让静态方法拥有正确的类型定义。

Question

是否存在一个对TypeScript友好的变通办法,在保持 timestamps 和虚拟填充的同时,能够正确对 this 进行类型标注?

任何解决方案、代码片段或最佳实践都会非常有帮助!

解决方案

问题之所以出现,是因为 SchemaOptions 在类型层面把虚拟字段和时间戳组合在一起,而Mongoose的推断引擎无法真正调和 DefaultTimestampProps 与虚拟填充的类型签名之间的关系。当两者都在 SchemaOptions 中时,冲突会传播到静态方法推断出的 this 类型。

你可以 使用 schema.virtual() + schema.static() 来修复它

interface IssueOneDoc {
  placeholder?: string;
}

const issueOneSchema = new mongoose.Schema<IssueOneDoc>(
  { placeholder: String },
  { timestamps: true }
);

// Define virtual after schema creation
issueOneSchema.virtual('votes', {
  ref: 'IssueTwo',
  localField: '_id',
  foreignField: 'issueOneId'
});

// Define static after schema creation
issueOneSchema.static('myStaticMethod', function () {
  console.log('placeholder');
});

const IssueOne = mongoose.model('IssueOne', issueOneSchema);

IssueOne.myStaticMethod();

备选方案

来自Mongoose维护者的一个 变通方案

作为一个变通办法,使用Schema.create() 代替new Schema() —— Schema.create() 在运行时等价,但具有更强的TypeScript推断能力。以下代码可以正确编译。我们正在研究可以做些什么来修复new Schema() 的推断。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章