TSC无法识别Mongoose Schema中Virtual属性的问题求助
解决Mongoose虚拟属性在TypeScript中无法被InferSchemaType识别的问题
问题原因
InferSchemaType工具仅会基于Schema中定义的持久化存储字段生成类型,不管是在Schema配置的virtuals选项里定义的,还是用.virtual()方法添加的虚拟属性,都不会被自动包含到生成的类型中,因此TS会抛出TS2339属性不存在的错误。
解决方案
方法1:手动扩展接口类型
在InferSchemaType生成的基础类型上,手动添加虚拟属性的类型定义:
import {connect, InferSchemaType, Schema, model} from 'mongoose'; const url = 'mongodb://admin:admin@0.0.0.0:27017/'; export const DBS_Actor = new Schema( { firstName: String, lastName: String, }, { virtuals: { fullName: { get() { return this.firstName + ' ' + this.lastName; }, }, }, } ); DBS_Actor.virtual('tagname').get(function () { return 'Secrete Agent 007'; }); // 生成基础持久化字段类型 type IActorBase = InferSchemaType<typeof DBS_Actor>; // 手动添加虚拟属性的类型 export interface IActor extends IActorBase { fullName: string; tagname: string; } // 将扩展后的接口传入model export const Actor = model<IActor>('User', DBS_Actor); run().catch(err => console.log(err)); async function run() { await connect(url); const actor = new Actor({ firstName: 'jojo', lastName: 'kiki', }); await actor.save(); console.log(actor.toJSON()); console.log(actor.firstName); console.log(actor.fullName); // TS不再报错 console.log(actor.tagname); // TS不再报错 }
方法2:结合HydratedDocument定义实例类型
Mongoose的Model实例本质是HydratedDocument类型,它包含了文档方法、虚拟属性等扩展内容,适合更严谨的类型定义:
import {connect, InferSchemaType, Schema, model, HydratedDocument} from 'mongoose'; const url = 'mongodb://admin:admin@0.0.0.0:27017/'; export const DBS_Actor = new Schema( { firstName: String, lastName: String, }, { virtuals: { fullName: { get() { return this.firstName + ' ' + this.lastName; }, }, }, } ); DBS_Actor.virtual('tagname').get(function () { return 'Secrete Agent 007'; }); type IActorBase = InferSchemaType<typeof DBS_Actor>; interface IActor extends IActorBase { fullName: string; tagname: string; } // 定义包含虚拟属性的实例类型 type ActorDocument = HydratedDocument<IActor>; export const Actor = model<IActor>('User', DBS_Actor); run().catch(err => console.log(err)); async function run() { await connect(url); const actor: ActorDocument = new Actor({ firstName: 'jojo', lastName: 'kiki', }); await actor.save(); console.log(actor.toJSON()); console.log(actor.firstName); console.log(actor.fullName); console.log(actor.tagname); }
注意点
- 检查虚拟属性的大小写:你代码中注释写的是
actor.fullname,但定义的是fullName,大小写不一致也会触发错误,需保持统一。 - 如果虚拟属性包含setter,需在接口中补充对应的方法类型(按需添加)。
内容的提问来源于stack exchange,提问作者Yuval Dimnik
相关产品推荐
相关产品推荐

