針對模型類型部分結構進行操作
當使用 Prisma Client 時,您 Prisma schema 中的每個模型都會被翻譯成專用的 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
}
從此 schema 生成的 Prisma Client 程式碼包含 User
類型的此表示形式
export declare type User = {
id: string
email: string
name: string | null
}
問題:使用生成的模型類型的變體
描述
在某些情況下,您可能需要生成的 User
類型的變體。例如,當您有一個函數期望 User
模型的實例,該實例帶有 posts
關聯。或者當您需要一個類型僅在您的應用程式碼中傳遞 User
模型的 email
和 name
欄位時。
解決方案
作為解決方案,您可以使用 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 變更時的維護負擔,因為您需要手動維護這些類型。一個更簡潔的解決方案是使用 UserGetPayload
類型,該類型由 Prisma Client 在 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 Client 生成的類型
- 當 schema 變更時,減少維護負擔並提高類型安全性
問題:取得函數的返回類型
描述
當對您的模型執行 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>