Mongoose与 TypeScript
TypeScript this 错误:在Mongoose静态方法中处理 timestamps +虚拟填充
Question
我正在使用 Mongoose 9.2.2 与 TypeScript 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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。