如何让函数返回类型依赖于Prisma对象中的关联关系
问题描述
需要实现一个接收Prisma App 对象的函数,函数返回的 AppVersion 类型需根据传入对象中 versions 关联的包含情况自动推导:
- 当
versions包含pages、variables、actions关联时,返回类型需包含这些属性 - 当
versions未包含这些关联时,返回类型不包含这些属性
以下是初始实现尝试及对应的Prisma Schema:
初始实现代码
import { Prisma } from "@prisma/client"; const getVersion = < Relations extends Prisma.AppVersionInclude, App extends Prisma.AppGetPayload<{ include: { versions: { include: Relations } }; }>, >( app: App, ): Prisma.AppVersionGetPayload<{ include: Relations }> => { return app.versions[0]!; }; const withRelations = await prisma.app.findUnique({ where: { id: "foo" }, include: { versions: { include: { pages: true, variables: true, actions: true, }, }, }, }); const withoutRelations = await prisma.app.findUnique({ where: { id: "foo" }, include: { versions: true, }, }); const versionWithRelations = getVersion(withRelations!); const versionWithoutRelations = getVersion(withoutRelations!); // 期望的类型: // typeof versionWithRelations type VersionWithRelations = { id: string; appId: string; majorVersion: number; minorVersion: number; patchVersion: number; pages: { id: string; appVersionId: string; path: string; description: string; }[]; variables: { id: string; appVersionId: string; name: string; description: string; }[]; actions: { id: string; appVersionId: string; name: string; description: string; }[]; } // typeof versionWithoutRelations type VersionWithoutRelations = { id: string; appId: string; majorVersion: number; minorVersion: number; patchVersion: number; }
Prisma Schema
model App { id String @id @default(cuid()) name String versions AppVersion[] } model AppVersion { id String @id @default(cuid()) appId String majorVersion Int minorVersion Int patchVersion Int pages AppPage[] variables AppVariable[] actions AppAction[] app App @relation(fields: [appId], references: [id], onDelete: Cascade) @@unique([appId, majorVersion, minorVersion, patchVersion]) } model AppPage { id String @id @default(cuid()) appVersionId String path String description String appVersion AppVersion @relation(fields: [appVersionId], references: [id], onDelete: Cascade) @@unique([appVersionId, path]) } model AppVariable { id String @id @default(cuid()) appVersionId String name String description String appVersion AppVersion @relation(fields: [appVersionId], references: [id], onDelete: Cascade) @@unique([appVersionId, name]) } model AppAction { id String @id @default(cuid()) appVersionId String name String description String appVersion AppVersion @relation(fields: [appVersionId], references: [id], onDelete: Cascade) @@unique([appVersionId, name]) }
解决方案
可以简化泛型定义,直接从传入的 app 对象中提取 versions 的元素类型,让 TypeScript 自动推导返回类型,无需手动关联 Prisma.AppVersionInclude:
import { Prisma } from "@prisma/client"; // 泛型 T 直接对应 AppVersion 的具体类型(包含或不包含关联) const getVersion = <T extends Prisma.AppVersion>(app: { versions: T[] }) => { return app.versions[0]!; }; // 使用方式不变 const withRelations = await prisma.app.findUnique({ where: { id: "foo" }, include: { versions: { include: { pages: true, variables: true, actions: true }, }, }, }); const withoutRelations = await prisma.app.findUnique({ where: { id: "foo" }, include: { versions: true }, }); const versionWithRelations = getVersion(withRelations!); const versionWithoutRelations = getVersion(withoutRelations!);
解释
- 泛型
T会自动适配传入app对象中versions数组的元素类型:- 当传入包含关联的
withRelations时,T就是包含pages、variables、actions的AppVersion类型 - 当传入不带关联的
withoutRelations时,T就是基础的AppVersion类型
- 当传入包含关联的
- 这种写法更简洁,完全利用 TypeScript 的类型推导能力,避免了手动维护
Relations泛型与App类型的关联,同时精准满足需求。
内容的提问来源于stack exchange,提问作者Magnar Myrtveit
相关产品推荐
相关产品推荐

