Prisma/TypeScript扩展客户端遇类型错误,求解决方案
问题原因与解决方案
一、findMany调用报错的原因与修复
报错原因
TypeScript无法在联合类型的模型客户端之间,将传入的model参数和对应的findMany参数类型建立关联。虽然泛型约束了A是对应模型findMany的参数,但TypeScript处理联合类型时,会把this[model]视为所有模型客户端的联合,每个findMany的签名都不兼容,因此抛出“联合类型成员签名无法匹配”的错误。
修复代码
通过类型断言缩小this[model]的类型范围,让TypeScript明确它是对应模型的客户端,从而匹配参数类型:
import { PrismaClient } from '@prisma/client'; export type NotStartsWith< S, Prefix extends string, > = S extends `${Prefix}${infer _X}` ? never : S; // 定义模型客户端与模型名的类型映射 type ModelClient<T extends PrismaClient> = { [K in NotStartsWith<keyof T, '$'>]: T[K] }; export class DatabaseService extends PrismaClient { async $findPaginated< M extends NotStartsWith<keyof DatabaseService, '$'>, A extends Parameters<ModelClient<DatabaseService>[M]['findMany']>[0], >(model: M, args?: A) { // 断言为对应模型的客户端,消除联合类型歧义 const modelClient = this[model] as ModelClient<DatabaseService>[M]; const data = await modelClient.findMany(args); return { page: 1, results: data, total: 1, totalPages: 1, }; } }
二、给所有模型添加通用方法的最优方案
不建议通过继承PrismaClient扩展,推荐使用Prisma官方支持的$extendsAPI,它能自动为所有模型注入通用方法并生成正确的类型:
import { PrismaClient } from '@prisma/client'; // 扩展所有模型的通用方法 const prisma = new PrismaClient().$extends({ model: { $allModels: { async findPaginated(args?: Parameters<typeof this.findMany>[0]) { const data = await this.findMany(args); return { page: 1, results: data, total: 1, totalPages: 1, }; }, // 可添加更多通用方法 async findUniqueExtended(args?: Parameters<typeof this.findUnique>[0]) { return this.findUnique(args); } }, }, }); // 使用示例:每个模型都能调用通用方法,参数自动补全 async function test() { const posts = await prisma.post.findPaginated({ where: { authorId: 1 } }); const users = await prisma.user.findPaginated({ take: 10 }); }
$allModels会将方法注入到所有模型客户端,this指向具体模型实例,TypeScript会自动推断方法的参数与返回值类型,完全满足类型安全需求。
内容的提问来源于stack exchange,提问作者random42
相关产品推荐
相关产品推荐

