跳至主要內容

類型安全

Prisma Client 所產生的程式碼包含數種實用的型別與工具,您可以利用這些功能來提升應用程式的型別安全。本頁面將介紹如何運用這些功能的模式。

注意:如果您對 Prisma ORM 的進階型別安全主題感興趣,請務必查看這篇關於如何使用新的 TypeScript satisfies 關鍵字來改善 Prisma Client 工作流程的部落格文章

匯入產生的型別

您可以匯入 Prisma 命名空間,並使用點記法(dot notation)來存取各種類型與工具。以下範例顯示如何匯入 Prisma 命名空間,並藉此存取與使用 Prisma.UserSelect 產生的型別

import { Prisma } from '@prisma/client'

// Build 'select' object
const userEmail: Prisma.UserSelect = {
email: true,
}

// Use select object
const createUser = await prisma.user.create({
data: {
email: 'bob@prisma.io',
},
select: userEmail,
})

另請參閱:使用 Prisma.UserCreateInput 產生的型別

什麼是產生的型別?

產生的型別是從您的資料模型衍生而來的 TypeScript 型別。您可以使用這些型別來建立型別化的物件,並將其傳入頂層方法(例如 prisma.user.create(...)prisma.user.update(...)),或是傳入諸如 selectinclude 等選項中。

例如,select 會接收一個 UserSelect 型別的物件。其物件屬性必須符合模型中 select 陳述式所支援的欄位。

下方的第一個分頁顯示了 UserSelect 產生的型別,以及該物件上的每個屬性如何具備型別註解。第二個分頁則顯示產出該型別的原始 Schema。

type Prisma.UserSelect = {
id?: boolean | undefined;
email?: boolean | undefined;
name?: boolean | undefined;
posts?: boolean | Prisma.PostFindManyArgs | undefined;
profile?: boolean | Prisma.ProfileArgs | undefined;
}

在 TypeScript 中,型別註解 (type annotations) 是指在宣告變數時加入型別註解,以描述該變數的型別。請參閱下方範例。

const myAge: number = 37
const myName: string = 'Rich'

這兩個變數宣告都已加上型別註解,分別指定其原始型別為 numberstring。大多數情況下,此類註解是不必要的,因為 TypeScript 會根據變數的初始值來推斷其型別。在上方的範例中,myAge 初始化為一個數字,因此 TypeScript 會推測其型別應為數字。

回到 UserSelect 型別,如果您在建立的 userEmail 物件上使用點記法,您將能夠存取 User 模型中所有可透過 select 陳述式進行互動的欄位。

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
profile Profile?
}
import { Prisma } from '@prisma/client'

const userEmail: Prisma.UserSelect = {
email: true,
}

// properties available on the typed object
userEmail.id
userEmail.email
userEmail.name
userEmail.posts
userEmail.profile

同樣地,您也可以使用 include 產生的型別來定義物件,這樣您的物件就能存取那些可以使用 include 陳述式的屬性。

import { Prisma } from '@prisma/client'

const userPosts: Prisma.UserInclude = {
posts: true,
}

// properties available on the typed object
userPosts.posts
userPosts.profile

請參閱模型查詢選項 (model query options) 參考文件,以了解更多可用的型別資訊。

產生的 UncheckedInput 型別

UncheckedInput 型別是一組特殊的產生型別,允許您執行 Prisma Client 認為「不安全」的操作,例如直接寫入關聯純量欄位 (relation scalar fields)。在執行 createupdateupsert 等操作時,您可以選擇「安全」的 Input 型別或「不安全」的 UncheckedInput 型別。

例如,此 Prisma Schema 在 UserPost 之間定義了一對多關聯:

model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
content String?
author User @relation(fields: [authorId], references: [id])
authorId Int
}

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

第一個分頁顯示 PostUncheckedCreateInput 產生的型別。它包含 authorId 屬性,這是一個關聯純量欄位。第二個分頁顯示一個使用 PostUncheckedCreateInput 型別的範例查詢。如果 id1 的使用者不存在,此查詢將會導致錯誤。

type PostUncheckedCreateInput = {
id?: number
title: string
content?: string | null
authorId: number
}

相同的查詢可以使用更「安全」的 PostCreateInput 型別來重寫。此型別不包含 authorId 欄位,而是改為包含 author 關聯欄位。

type PostCreateInput = {
title: string
content?: string | null
author: UserCreateNestedOneWithoutPostsInput
}

type UserCreateNestedOneWithoutPostsInput = {
create?: XOR<
UserCreateWithoutPostsInput,
UserUncheckedCreateWithoutPostsInput
>
connectOrCreate?: UserCreateOrConnectWithoutPostsInput
connect?: UserWhereUniqueInput
}

如果 id1 的作者不存在,此查詢同樣會導致錯誤。在這種情況下,Prisma Client 將會提供更具描述性的錯誤訊息。您也可以使用 connectOrCreate API,在給定 id 的使用者不存在時,安全地建立一個新使用者。

我們建議盡可能使用「安全」的 Input 型別。

型別工具

資訊

此功能適用於 Prisma ORM 4.9.0 及更高版本。

為了協助您建立高度型別安全的應用程式,Prisma Client 提供了一組能對接輸入與輸出型別的型別工具。這些型別是完全動態的,代表它們會適應任何給定的模型與 Schema。您可以使用它們來改善專案的自動完成功能與開發者體驗。

這在驗證輸入共用的 Prisma Client 擴充功能中特別有用。

Prisma Client 提供以下型別工具:

  • Exact<Input, Shape>:對 Input 強制執行嚴格的型別安全。Exact 確保泛型型別 Input 嚴格遵守您在 Shape 中指定的型別。它會將 Input 縮窄 (narrowing) 為最精確的型別。
  • Args<Type, Operation>:擷取給定模型與操作的輸入引數。這對於想要執行以下動作的擴充功能作者特別有用:
    • 重複使用現有型別以進行擴充或修改。
    • 享有與現有操作相同的自動完成體驗。
  • Result<Type, Arguments, Operation>:接收輸入引數並提供給定模型與操作的結果。通常會與 Args 搭配使用。如同 ArgsResult 協助您重複使用現有型別來進行擴充或修改。
  • Payload<Type, Operation>:擷取結果的完整結構,包含給定模型與操作的純量與關聯物件。例如,您可以使用此功能在型別層級判斷哪些鍵是純量或物件。

作為範例,以下是一個快速的方法,確保函數的引數與您將傳遞給 post.create 的內容相符:

type PostCreateBody = Prisma.Args<typeof prisma.post, 'create'>['data']

const addPost = async (postBody: PostCreateBody) => {
const post = await prisma.post.create({ data: postBody })
return post
}

await addPost(myData)
// ^ guaranteed to match the input of `post.create`
© . This site is unofficial and not affiliated with Prisma Data, Inc.