如何缩小Prisma查询返回的type字段类型范围?
问题:Prisma连接MSSQL时,如何将String类型字段收窄为自定义联合类型?
我有如下Prisma Schema:
model Example { id String @id @default(cuid()) createdOn DateTime @default(now()) type String }
type字段只能取以下值之一:
const Types = [ "createdLicense", "archivedLicense", "updateProcessingType", ... ] as const; type HistoryType = (typeof Types)[number];
因为使用Prisma连接MSSQL数据库,无法使用Prisma的枚举类型。插入数据时,我通过satisfies运算符确保type字段无拼写错误:
type: "archivedLicense" satisfies HistoryType,
这种方式插入时没问题,但查询时存在问题:返回的type字段类型为string,范围过宽。我尝试扩展Prisma客户端,但当前方案无效:
const custom = prisma.$extends({ name: "example", query: { example: { async findMany({ model, args, operation, query }) { const queryResult = await query(args); return queryResult.map((item) => { return { ...item, type: item.type as HistoryType, }; }); }, }, }, });
执行后返回的type类型仍然是string。
解决方案
1. 使用Prisma扩展的result钩子收窄类型
要同时在类型系统和运行时实现字段类型收窄,应该使用Prisma扩展的result字段,而非query钩子。result会直接修改Prisma生成的类型定义,同时可以添加运行时校验确保数据合法性:
const Types = [ "createdLicense", "archivedLicense", "updateProcessingType", ... ] as const; type HistoryType = (typeof Types)[number]; // 运行时校验函数,确保返回的type属于允许的集合 const isHistoryType = (value: unknown): value is HistoryType => { return typeof value === 'string' && (Types as readonly string[]).includes(value); }; const customPrisma = prisma.$extends({ result: { example: { type: { needs: { type: true }, // 声明需要获取原始的type字段值 compute(item) { const rawType = item.type; if (!isHistoryType(rawType)) { throw new Error(`无效的type值:${rawType}`); } return rawType; }, }, }, }, });
2. 为什么之前的query方案无效?
之前的query钩子只是在运行时修改了返回值,但TypeScript仍然沿用Prisma Client生成的原始类型定义,所以编译时和IDE中type还是显示为string。而result扩展会直接更新Prisma的类型系统,让type字段的类型被正确收窄为HistoryType。
3. 优势:自动覆盖所有查询操作
result扩展会自动应用到所有返回Example模型的查询(比如findUnique、findFirst、findMany、update返回值等),不需要为每个查询操作单独编写钩子,更高效。
内容的提问来源于stack exchange,提问作者radmacher
相关产品推荐
相关产品推荐

