You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让函数返回类型依赖于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:43:17