跳到主要内容

对模型类型的局部结构进行操作

当使用 Prisma Client 时,您 Prisma schema 中的每个模型都会被转换为专用的 TypeScript 类型。 例如,假设您有以下 UserPost 模型

model User {
id Int @id
email String @unique
name String?
posts Post[]
}

model Post {
id Int @id
author User @relation(fields: [userId], references: [id])
title String
published Boolean @default(false)
userId Int
}

从该 schema 生成的 Prisma Client 代码包含 User 类型的这种表示形式

export type User = {
id: string
email: string
name: string | null
}

问题:使用生成的模型类型的变体

描述

在某些情况下,您可能需要生成的 User 类型的变体。 例如,当您有一个函数期望一个带有 posts 关系的 User 模型实例时。 或者当您需要一个类型来仅在您的应用程序代码中传递 User 模型的 emailname 字段时。

解决方案

作为解决方案,您可以使用 Prisma Client 的辅助类型来自定义生成的模型类型。

User 类型仅包含模型的标量字段,但不考虑任何关系。 这是因为 默认情况下,关系不包含在 Prisma Client 查询中。

但是,有时拥有一个可用的类型非常有用,该类型包含关系(即,您从使用 include 的 API 调用中获得的类型)。 同样,另一个有用的场景可能是拥有一个可用的类型,该类型仅包含模型标量字段的子集(即,您从使用 select 的 API 调用中获得的类型)。

实现此目的的一种方法是在您的应用程序代码中手动定义这些类型

// 1: Define a type that includes the relation to `Post`
type UserWithPosts = {
id: string
email: string
name: string | null
posts: Post[]
}

// 2: Define a type that only contains a subset of the scalar fields
type UserPersonalData = {
email: string
name: string | null
}

虽然这当然是可行的,但这种方法会增加 Prisma schema 更改时的维护负担,因为您需要手动维护这些类型。 一个更简洁的解决方案是结合 validator 使用由 Prisma Client 在 Prisma 命名空间下生成和公开的 UserGetPayload 类型。

以下示例使用 Prisma.validator 创建两个类型安全的对象,然后使用 Prisma.UserGetPayload 实用程序函数创建一个可用于返回所有用户及其帖子的类型。

import { Prisma } from '@prisma/client'

// 1: Define a type that includes the relation to `Post`
const userWithPosts = Prisma.validator<Prisma.UserDefaultArgs>()({
include: { posts: true },
})

// 2: Define a type that only contains a subset of the scalar fields
const userPersonalData = Prisma.validator<Prisma.UserDefaultArgs>()({
select: { email: true, name: true },
})

// 3: This type will include a user and all their posts
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>

后一种方法的主要优点是

  • 更简洁的方法,因为它利用了 Prisma Client 生成的类型
  • 当 schema 更改时,减少了维护负担并提高了类型安全性

问题:访问函数的返回类型

描述

当在您的模型上执行 selectinclude 操作并从函数返回这些变体时,可能难以访问返回类型,例如

// Function definition that returns a partial structure
async function getUsersWithPosts() {
const users = await prisma.user.findMany({ include: { posts: true } })
return users
}

从上面的代码片段中提取表示“带有帖子的用户”的类型需要一些高级 TypeScript 用法

// Function definition that returns a partial structure
async function getUsersWithPosts() {
const users = await prisma.user.findMany({ include: { posts: true } })
return users
}

// Extract `UsersWithPosts` type with
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T
type UsersWithPosts = ThenArg<ReturnType<typeof getUsersWithPosts>>

// run inside `async` function
const usersWithPosts: UsersWithPosts = await getUsersWithPosts()

解决方案

使用 Prisma 命名空间公开的 PromiseReturnType,您可以更优雅地解决此问题

import { Prisma } from '@prisma/client'

type UsersWithPosts = Prisma.PromiseReturnType<typeof getUsersWithPosts>