Mongoose + TypeScript 条件调用模型find方法报联合类型不兼容错误
问题根因
你定义的PictureModel和VideoModel是两个携带不同泛型参数的Mongoose Model类型,当你用三元表达式把它们赋值给model变量时,TypeScript会把model推导为两个Model的联合类型。这两个Model的find方法签名因为泛型参数不同(返回的Document类型分别是PictureDocument和VideoDocument),TypeScript判定它们的签名不兼容,所以调用的时候会抛出类型错误。
解决方案
方案1:提前分支返回(最推荐,无类型hack,完全类型安全)
不要先合并成联合类型的model变量,直接在条件判断分支里执行查询并返回:
const getDocuments = async (condition: "picture" | "video") => { if (condition === "picture") { return await PictureModel.find().exec(); } return await VideoModel.find().exec(); };
这种写法下每个分支的Model类型都是明确的,TypeScript不会报错,同时返回值会被自动推导为PictureDocument[] | VideoDocument[],不需要额外的类型处理。
方案2:类型断言统一Model类型(适合不想改动原有代码结构的场景)
如果确实需要先拿到统一的model变量再执行查询,可以手动将联合类型的Model断言为携带公共父类泛型的Model类型:
import type { Model, Document } from "mongoose"; const getDocuments = async (condition: "picture" | "video") => { const model = (condition === "picture" ? PictureModel : VideoModel) as Model<Document>; return await model.find().exec(); };
如果需要保留精确的返回类型,可以手动标注函数返回值:
const getDocuments = async (condition: "picture" | "video"): Promise<PictureDocument[] | VideoDocument[]> => { const model = (condition === "picture" ? PictureModel : VideoModel) as Model<Document>; return await model.find().exec() as PictureDocument[] | VideoDocument[]; };
方案3:泛型封装(适合需要动态关联入参和返回类型的场景)
如果希望传入picture时返回值自动推导为PictureDocument[],传入video时自动推导为VideoDocument[],可以用泛型做类型映射:
import type { Model } from "mongoose"; type ConditionTypeMap = { picture: PictureDocument, video: VideoDocument } const getDocuments = async <T extends keyof ConditionTypeMap>(condition: T): Promise<ConditionTypeMap[T][]> => { const model = (condition === "picture" ? PictureModel : VideoModel) as Model<ConditionTypeMap[T]>; return await model.find().exec(); }; // 调用时返回类型自动推导:const res: PictureDocument[] const res = await getDocuments("picture");
小提示:你当前代码里定义
PictureModel时,model方法的第一个参数集合名写错成了video,实际应该改成picture,否则两个模型会操作同一个集合。
内容的提问来源于stack exchange,提问作者Sir hennihau
相关产品推荐
相关产品推荐

