操作模型类型的部分结构
当使用 Prisma 客户端时,您的Prisma 模式中的每个模型都会被转换为一个专门的 TypeScript 类型。例如,假设您有以下User
和Post
模型
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
}
从该模式生成的 Prisma 客户端代码包含User
类型的这种表示形式
export declare type User = {
id: string
email: string
name: string | null
}
问题:使用生成的模型类型的变体
描述
在某些情况下,您可能需要生成的User
类型的变体。例如,当您有一个函数,该函数期望User
模型的一个实例,该实例带有posts
关系时。或者当您需要一个类型来仅将User
模型的email
和name
字段传递到您的应用程序代码中时。
解决方案
作为解决方案,您可以使用 Prisma 客户端的辅助类型来定制生成的模型类型。
User
类型仅包含模型的标量字段,但没有考虑任何关系。这是因为关系默认情况下不会包含在 Prisma 客户端查询中。
但是,有时有必要有一个类型可用,该类型包含一个关系(即,您从使用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 模式时会增加维护负担,因为您需要手动维护类型。一个更简洁的解决方案是使用UserGetPayload
类型,该类型是由 Prisma 客户端生成的,并在Prisma
命名空间下公开,并与validator
结合使用。
以下示例使用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 客户端的生成类型
- 当模式发生变化时,减少维护负担并提高类型安全性
问题:获取对函数返回值类型的访问权限
描述
当在您的模型上执行select
或include
操作并将这些变体从函数返回时,可能难以获得对返回值类型的访问权限,例如
// 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>