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

如何修复类型'IUser & { _id: any; }'不存在属性'_doc'的TS报错

报错原因

Mongoose 查询返回的是包装后的 Document 实例对象,_doc 是实例上存储原始文档字段的内部属性,Mongoose 官方公开的 TypeScript 类型定义中没有将该内部属性纳入 Document 类型的公开声明,直接访问会触发类型报错。

手动在 IUser 接口中添加 _doc 属性定义不会对 User 数据库模型、实际运行逻辑造成任何影响——TypeScript 类型仅在编译阶段做校验,不会侵入运行时的 Schema 定义或数据库存储结构,但这种写法会将 Mongoose 内部属性暴露到业务类型定义中,且 _doc 不属于公开稳定API,版本迭代时可能出现结构变动,存在兼容隐患。

推荐解决方案

方案1:使用官方toObject()方法(通用场景)

Mongoose Document 实例自带公开的 toObject() 方法,作用就是将包装后的文档实例转换为普通JavaScript对象,自动剥离Mongoose内置的实例方法、内部属性,返回值类型会自动匹配IUser中定义的字段,无需修改现有接口定义。

修改后的resolver代码:

import User from '../models/User'
import { GraphQLResolveInfo } from 'graphql'

const resolvers = {
  Query: {
    users (parent: any, args: any, context: any, info: GraphQLResolveInfo) {
      return User.find()
        .then (userList => {
          return userList.map(r => r.toObject())
        })
    }
  }
}

如果需要隐藏默认返回的__v版本键、转换_id格式,可以传入配置项:

r.toObject({ versionKey: false, getters: true })

方案2:查询时添加lean()选项(列表查询最优)

如果查询出的文档不需要调用save()等Mongoose实例方法,可以在查询链中调用.lean(),Mongoose会直接返回普通JS对象数组,不会生成Document实例,从根源上规避内部属性访问问题,同时查询性能比返回Document实例高3-5倍,非常适合GraphQL接口只返回数据的场景。

修改后的resolver代码:

import User from '../models/User'
import { GraphQLResolveInfo } from 'graphql'

const resolvers = {
  Query: {
    users (parent: any, args: any, context: any, info: GraphQLResolveInfo) {
      // 加lean()后直接返回普通对象,无需额外解构
      return User.find().lean()
    }
  }
}

方案3:临时类型断言(不推荐)

如果一定要直接解构_doc,不需要修改IUser接口定义,在访问时做类型断言即可,不会产生运行时影响:

return user.map (r => ({
  ...(r._doc as IUser)
}))

该方案仅适合临时快速修复,长期维护不建议使用,因为内部属性无稳定API承诺,版本升级可能出现非预期问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 06:19:28