如何让Prisma的include关联查询结果兼容TypeScript类型?
Prisma关联查询的TypeScript类型兼容问题解决
问题描述
执行带include的关联查询:
await prisma.song.findMany({ include: { artist: true } })
Prisma会将关联的artist数据添加到song.artist字段,但默认生成的Song TypeScript类型仅包含模型的直接字段,没有.artist属性,导致报错:
Property 'artist' does not exist on type {type definition for song}
解决方案
完全可以生成包含关联扩展的类型,以下是两种常用方案:
1. 使用Prisma自动推导的嵌套类型(推荐)
Prisma会根据你的查询配置自动生成对应的类型,通过Prisma.ModelNameGetPayload工具类型就能获取包含关联的完整类型:
import { Prisma } from '@prisma/client'; // 定义查询的包含配置并标记为常量,让TypeScript保留类型细节 const includeArtistConfig = { include: { artist: true } } as const; // 推导包含artist后的Song类型 type SongWithArtist = Prisma.SongGetPayload<typeof includeArtistConfig>; // 直接使用推导后的类型 const songs: SongWithArtist[] = await prisma.song.findMany(includeArtistConfig); // 此时访问song.artist完全符合TypeScript类型规范 songs.forEach(song => console.log(song.artist.name));
2. 手动扩展类型(适合特殊场景)
如果需要自定义类型结构,可以手动扩展基础Song类型:
import { Song, Artist } from '@prisma/client'; // 合并基础Song类型和关联的Artist类型 type SongWithArtist = Song & { artist: Artist; }; // 查询时通过类型断言指定结果类型 const songs = await prisma.song.findMany({ include: { artist: true } }) as SongWithArtist[];
这种方式需要手动维护类型同步,当模型字段或关联关系变更时容易出错,仅在自动推导无法满足需求时使用。
进阶:封装复用带类型的查询
如果某个关联查询频繁使用,可以通过Prisma客户端扩展封装成方法,固化类型:
import { PrismaClient, Prisma } from '@prisma/client'; const prisma = new PrismaClient().$extends({ model: { song: { async findManyWithArtist() { return prisma.song.findMany({ include: { artist: true } }) as Prisma.SongGetPayload<{ include: { artist: true } }>[]; } } } }); // 调用封装方法时直接获得正确类型 const songs = await prisma.song.findManyWithArtist();
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

