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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:57:17