跳到主要內容

針對模型類型部分結構進行操作

當使用 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 declare type User = {
id: string
email: string
name: string | null
}

問題:使用生成的模型類型的變體

描述

在某些情況下,您可能需要生成的 User 類型的變體。例如,當您有一個函數期望 User 模型的實例,該實例帶有 posts 關聯。或者當您需要一個類型僅在您的應用程式碼中傳遞 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 變更時的維護負擔,因為您需要手動維護這些類型。一個更簡潔的解決方案是使用 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 變更時,減少維護負擔並提高類型安全性

問題:取得函數的返回類型

描述

當對您的模型執行 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>