TypeScript联合类型异常 Prisma委托调用findUnique触发类型报错
问题原因
TypeScript 对联合类型上的函数成员调用有明确的类型检查规则:当一个值是A | B的联合类型时,访问该值上的方法会得到A的方法 | B的方法的函数联合类型;调用函数联合类型时,传入的参数必须同时兼容所有联合分支的函数参数签名,TS才会认为调用合法——因为编译阶段无法确定运行时拿到的到底是A还是B类型的实例,只能要求参数满足所有可能的分支要求。
Prisma 为每个模型生成的Delegate(委托对象)类型是独立的标称类型,哪怕SaleOffer和RentOffer的数据库字段完全一致,二者的findUnique、findMany等方法的入参(where条件、select配置等)、返回值类型都是独立、不自动兼容的。当你把函数返回值定义为PrismaClient['SaleOffer'] | PrismaClient['RentOffer']时,调用findUnique就需要传入同时满足两个模型过滤规则的参数,实际业务里几乎不可能满足这个要求,就会抛出类型错误。
当你把返回值断言为任意一个具体的Delegate类型时,TS只会按照单个模型的类型规则检查参数,自然不会报错。
修复方案
推荐优先级从高到低:
- 使用函数重载精确匹配入参和返回值
不需要做任何类型断言,TS会根据你传入的offerType值自动推导准确的Delegate类型,类型检查完全精准:// 重载签名 function prisma_delegate(offerType: 'sale'): PrismaClient['SaleOffer'] function prisma_delegate(offerType: 'rent'): PrismaClient['RentOffer'] // 实现签名 function prisma_delegate(offerType: 'sale' | 'rent') { return offerType === 'sale' ? prisma.saleOffer : prisma.rentOffer } // 调用时无类型错误,也不需要as断言 await prisma_delegate(offerType).findUnique({ where: { /* 传入对应模型合法的查询条件即可 */ } }) - 用泛型映射绑定入参与返回值类型
逻辑和重载一致,写法更简洁:type OfferTypeToDelegate = { sale: PrismaClient['SaleOffer'] rent: PrismaClient['RentOffer'] } const prisma_delegate = <T extends keyof OfferTypeToDelegate>( offerType: T ): OfferTypeToDelegate[T] => { const delegateMap: OfferTypeToDelegate = { sale: prisma.saleOffer, rent: prisma.rentOffer } return delegateMap[offerType] } - 提取公共Delegate类型(适合两个模型操作逻辑完全一致的场景)
用交叉类型合并两个Delegate的类型,得到的公共类型会包含二者所有同名方法的兼容签名,只要调用时使用两个模型共有的字段做查询,就不会触发类型错误:
注意这里必须用交叉类型type CommonOfferDelegate = PrismaClient['SaleOffer'] & PrismaClient['RentOffer'] const prisma_delegate = (offerType: 'sale' | 'rent'): CommonOfferDelegate => { return offerType === 'sale' ? prisma.saleOffer : prisma.rentOffer }&,不能用联合类型|。
不推荐继续使用类型断言绕开检查,会丢失TS的类型校验能力,容易引发出入参不匹配的运行时错误。
内容的提问来源于stack exchange,提问作者Sammy Mishal
相关产品推荐
相关产品推荐

