TypeScript对接Mongoose鉴别器模型遇类型推断问题,求解决方案
解决TypeScript与Mongoose鉴别器模型的类型推断问题
核心结论
可以通过正确配置接口和模型,让TypeScript自动推断鉴别器对应的具体类型,无需完全手动标注。
具体实现步骤
1. 定义带鉴别器字段的接口结构
先明确基础接口和各鉴别器子接口,将鉴别器字段(比如type)作为类型区分标识,子接口固定该字段的具体值:
import { Types } from 'mongoose'; // 基础接口,包含所有文档共享的字段和鉴别器字段 interface BaseDocument { _id: Types.ObjectId; type: 'user' | 'admin'; // 枚举所有可能的鉴别器类型 createdAt: Date; } // 用户子接口,固定鉴别器值为'user',添加专属字段 interface UserDocument extends BaseDocument { type: 'user'; username: string; email: string; } // 管理员子接口,固定鉴别器值为'admin',添加专属字段 interface AdminDocument extends BaseDocument { type: 'admin'; permissions: string[]; } // 联合类型,整合所有鉴别器文档类型 type AppDocument = UserDocument | AdminDocument;
2. 关联Mongoose模型与TypeScript类型
创建基础模型时传入联合类型,再基于它创建鉴别器模型并关联对应子接口:
import mongoose, { Schema, Model } from 'mongoose'; // 基础Schema,指定鉴别器字段 const baseSchema = new Schema<BaseDocument>({ type: { type: String, required: true }, createdAt: { type: Date, default: Date.now } }, { discriminatorKey: 'type' }); // 基础模型关联联合类型 const BaseModel: Model<AppDocument> = mongoose.model<AppDocument>('Base', baseSchema); // 创建用户鉴别器模型,关联UserDocument const UserModel = BaseModel.discriminator<UserDocument>( 'user', new Schema({ username: { type: String, required: true }, email: { type: String, required: true } }) ); // 创建管理员鉴别器模型,关联AdminDocument const AdminModel = BaseModel.discriminator<AdminDocument>( 'admin', new Schema({ permissions: [{ type: String, required: true }] }) );
3. 实现自动类型推断
通过鉴别器字段的类型守卫,TypeScript会自动推断文档的具体类型:
// 查询所有文档,返回AppDocument联合类型 const docs = await BaseModel.find({}); docs.forEach(doc => { if (doc.type === 'user') { // TS自动识别为UserDocument,可直接访问username、email console.log(doc.username); } else if (doc.type === 'admin') { // TS自动识别为AdminDocument,可直接访问permissions console.log(doc.permissions); } }); // 查询指定类型的文档,直接返回对应子类型数组 const adminDocs = await BaseModel.find({ type: 'admin' }); // adminDocs会被推断为AdminDocument[]
注意事项
- 子接口必须固定鉴别器字段的具体值,否则TS无法通过类型守卫完成自动推断。
- 若使用
lean()方法返回普通JS对象,需要手动指定返回类型:
const leanDocs = await BaseModel.find({}).lean<AppDocument[]>();
内容的提问来源于stack exchange,提问作者hornta
相关产品推荐
相关产品推荐

