型別安全
為 Prisma Client 生成的程式碼包含了一些有用的型別和實用工具,你可以用它們來使你的應用程式更具型別安全性。本頁描述瞭如何利用它們的模式。
注意:如果你對 Prisma ORM 的高階型別安全主題感興趣,請務必檢視這篇關於透過新的 TypeScript
satisfies關鍵字改進 Prisma Client 工作流的部落格文章。
匯入生成的型別
你可以匯入 Prisma 名稱空間,並使用點語法來訪問型別和實用工具。以下示例展示瞭如何匯入 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(...),或者傳遞給 select 或 include 等選項。
例如,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;
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
profile Profile?
}
在 TypeScript 中,型別註解的概念是當你宣告一個變數並新增一個型別註解來描述變數的型別時。參見下面的例子。
const myAge: number = 37
const myName: string = 'Rich'
這兩個變數宣告都已給定型別註解,分別指定它們的原始型別為 number 和 string。大多數時候,這種型別的註解是不需要的,因為 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
有關可用不同型別的更多資訊,請參閱模型查詢選項參考。
生成的 UncheckedInput 型別
UncheckedInput 型別是一組特殊的生成型別,允許你執行 Prisma Client 認為“不安全”的操作,例如直接寫入關係標量欄位。在進行 create、update 或 upsert 等操作時,你可以選擇“安全”的 Input 型別或“不安全”的 UncheckedInput 型別。
例如,這個 Prisma schema 在 User 和 Post 之間有一個一對多關係:
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 型別的查詢示例。如果 id 為 1 的使用者不存在,此查詢將導致錯誤。
- 生成型別
- 查詢示例
type PostUncheckedCreateInput = {
id?: number
title: string
content?: string | null
authorId: number
}
prisma.post.create({
data: {
title: 'First post',
content: 'Welcome to the first post in my blog...',
authorId: 1,
},
})
相同的查詢可以使用“更安全”的 PostCreateInput 型別重寫。此型別不包含 authorId 欄位,但包含 author 關係欄位。
- 生成型別
- 查詢示例
type PostCreateInput = {
title: string
content?: string | null
author: UserCreateNestedOneWithoutPostsInput
}
type UserCreateNestedOneWithoutPostsInput = {
create?: XOR<
UserCreateWithoutPostsInput,
UserUncheckedCreateWithoutPostsInput
>
connectOrCreate?: UserCreateOrConnectWithoutPostsInput
connect?: UserWhereUniqueInput
}
prisma.post.create({
data: {
title: 'First post',
content: 'Welcome to the first post in my blog...',
author: {
connect: {
id: 1,
},
},
},
})
如果 id 為 1 的作者不存在,此查詢也將導致錯誤。在這種情況下,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縮小到最精確的型別。Args<Type, Operation>:檢索任何給定模型和操作的輸入引數。這對於希望執行以下操作的擴充套件作者特別有用:- 重用現有型別以擴充套件或修改它們。
- 從與現有操作相同的自動補全體驗中獲益。
Result<Type, Arguments, Operation>:接受輸入引數併為給定模型和操作提供結果。你通常會將其與Args結合使用。與Args一樣,Result幫助你重用現有型別以擴充套件或修改它們。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`