Typegoose中getModelForClass返回值的构造、继承及自定义方法相关问题
问题1解答
首先要明确TypeScript的类型和运行时值是完全独立的两套体系:
ReturnModelType只是TypeScript定义的类型别名,仅在编译阶段做类型校验使用,编译成JavaScript后会被完全抹去,根本不是运行时真实存在的值,你直接拿它当构造函数new属于典型的把编译期类型当成运行时值使用的错误,自然会报错。getModelForClass是真实存在的运行时函数,它内部会根据你传入的Clip类生成标准的Mongoose Model构造函数,同时给这个构造函数标注上ReturnModelType<Clip, QueryHelpers>的TS类型。Mongoose的Model本身就是可被new调用的构造函数,所以你拿到的ClipModel既符合类型定义,运行时也确实支持构造实例,逻辑和原生Mongoose定义的Model完全一致。
问题2解答
ClipModel运行时确实是类(也就是Mongoose的Model构造函数),但它不符合TypeScript对可继承类的校验规则:
普通TS类的构造函数返回值是类本身的实例,而Mongoose Model的构造函数返回值是对应的MongoDB文档实例,和构造函数本身的类型不匹配。TS做继承校验时要求父类构造器的返回类型必须统一,因此抛出了这个错误。
另外Mongoose本身的设计就不推荐用继承Model的方式扩展功能,它有原生的静态方法、实例方法、查询助手等更符合设计规范的扩展方式。
问题3解答
完全可以,Typegoose原生支持给Model加自定义静态方法,不需要修改生成的Model,直接在你定义的Clip类里加静态方法即可:
import { prop, getModelForClass } from '@typegoose/typegoose'; class Clip { @prop() someProp?: string; // 直接定义静态方法,Typegoose会自动挂载到生成的Model上 static async myCustomFind(query: Record<string, any>) { // 这里写自定义逻辑,比如默认添加未删除的过滤条件 const mergedQuery = { isDeleted: false, ...query }; return this.find(mergedQuery); } } const ClipModel = getModelForClass(Clip); // 调用方式完全符合要求 ClipModel.find({}) // 原生默认方法 ClipModel.myCustomFind({}) // 自定义方法,TS类型会自动推导
如果是要扩展链式查询方法(比如find().myCustomFilter()这种形式),用Typegoose的查询助手装饰器即可实现。
内容的提问来源于stack exchange,提问作者Simon Verhoeven
相关产品推荐
相关产品推荐

