类型安全
Prisma Client 生成的代码包含几个有用的类型和实用程序,你可以使用它们使你的应用更加类型安全。本页描述了利用它们的模式。
¥The generated code for Prisma Client contains several helpful types and utilities that you can use to make your application more type-safe. This page describes patterns for leveraging them.
注意:如果你对 Prisma ORM 的高级类型安全主题感兴趣,请务必查看此 博客文章,了解如何使用新的 TypeScript
satisfies
关键字改进 Prisma 客户端工作流程。¥Note: If you're interested in advanced type safety topics with Prisma ORM, be sure to check out this blog post about improving your Prisma Client workflows with the new TypeScript
satisfies
keyword.
导入生成的类型
¥Importing generated types
你可以导入 Prisma
命名空间并使用点表示法来访问类型和实用程序。以下示例展示了如何导入 Prisma
命名空间并使用它来访问和使用 Prisma.UserSelect
生成类型:
¥You can import the Prisma
namespace and use dot notation to access types and utilities. The following example shows how to import the Prisma
namespace and use it to access and use the Prisma.UserSelect
generated type:
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
生成的类型
¥See also: Using the Prisma.UserCreateInput
generated type
什么是生成类型?
¥What are generated types?
生成的类型是从模型派生的 TypeScript 类型。你可以使用它们创建类型化对象,并将其传递到顶层方法(如 prisma.user.create(...)
或 prisma.user.update(...)
)或选项(如 select
或 include
)中。
¥Generated types are TypeScript types that are derived from your models. You can use them to create typed objects that you pass into top-level methods like prisma.user.create(...)
or prisma.user.update(...)
, or options such as select
or include
.
例如,select
接受 UserSelect
类型的对象。根据模型,其对象属性与 select
语句支持的对象属性相匹配。
¥For example, select
accepts an object of type UserSelect
. Its object properties match those that are supported by select
statements according to the model.
下面的第一个选项卡显示了 UserSelect
生成的类型以及对象上的每个属性如何具有类型注释。第二个选项卡显示生成类型的原始模式。
¥The first tab below shows the UserSelect
generated type and how each property on the object has a type annotation. The second tab shows the original schema from which the type was generated.
- Generated type
- Model
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 中,类型注释 的概念是声明变量并添加类型注释来描述变量的类型。请参阅下面的示例。
¥In TypeScript the concept of type annotations is when you declare a variable and add a type annotation to describe the type of the variable. See the below example.
const myAge: number = 37
const myName: string = 'Rich'
这两个变量声明都被赋予了类型注释来指定它们的基本类型,分别是 number
和 string
。大多数时候不需要这种注释,因为 TypeScript 会根据变量的初始化方式推断变量的类型。在上面的示例中,myAge
是用数字初始化的,因此 TypeScript 猜测它应该输入为数字。
¥Both of these variable declarations have been given a type annotation to specify what primitive type they are, number
and string
respectively. Most of the time this kind of annotation is not needed as TypeScript will infer the type of the variable based on how its initialized. In the above example myAge
was initialized with a number so TypeScript guesses that it should be typed as a number.
回到 UserSelect
类型,如果你要在创建的对象 userEmail
上使用点表示法,你将可以访问 User
模型上可以使用 select
语句进行交互的所有字段。
¥Going back to the UserSelect
type, if you were to use dot notation on the created object userEmail
, you would have access to all of the fields on the User
model that can be interacted with using a select
statement.
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
语句的那些属性。
¥In the same mould, you can type an object with an include
generated type then your object would have access to those properties on which you can use an include
statement.
import { Prisma } from '@prisma/client'
const userPosts: Prisma.UserInclude = {
posts: true,
}
// properties available on the typed object
userPosts.posts
userPosts.profile
有关可用的不同类型的更多信息,请参阅 模型查询选项 参考。
¥See the model query options reference for more information about the different types available.
生成的 UncheckedInput
类型
¥Generated UncheckedInput
types
UncheckedInput
类型是一组特殊的生成类型,允许你执行 Prisma Client 认为是 "unsafe" 的一些操作,例如直接写入 关系标量场。进行 create
、update
、upsert
等操作时,可以选择 "safe" Input
类型,也可以选择 "unsafe" UncheckedInput
类型。
¥The UncheckedInput
types are a special set of generated types that allow you to perform some operations that Prisma Client considers "unsafe", like directly writing relation scalar fields. You can choose either the "safe" Input
types or the "unsafe" UncheckedInput
type when doing operations like create
, update
, or upsert
.
例如,此 Prisma 模式在 User
和 Post
之间具有一对多关系:
¥For example, this Prisma schema has a one-to-many relation between User
and 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
的用户不存在,则此查询将导致错误。
¥The first tab shows the PostUncheckedCreateInput
generated type. It contains the authorId
property, which is a relation scalar field. The second tab shows an example query that uses the PostUncheckedCreateInput
type. This query will result in an error if a user with an id
of 1
does not exist.
- Generated type
- Example query
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,
},
})
可以使用 "safer" PostCreateInput
类型重写相同的查询。该类型不包含 authorId
字段,而是包含 author
关系字段。
¥The same query can be rewritten using the "safer" PostCreateInput
type. This type does not contain the authorId
field but instead contains the author
relation field.
- Generated type
- Example query
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 客户端将给出更具描述性的错误消息。如果给定的 id
尚不存在,你还可以使用 connectOrCreate
API 安全地创建新用户。
¥This query will also result in an error if an author with an id
of 1
does not exist. In this case, Prisma Client will give a more descriptive error message. You can also use the connectOrCreate
API to safely create a new user if one does not already exist with the given id
.
我们建议尽可能使用 "safe" Input
类型。
¥We recommend using the "safe" Input
types whenever possible.
类型实用程序
¥Type utilities
Prisma ORM 4.9.0 及以上版本提供此功能。
¥This feature is available from Prisma ORM version 4.9.0 upwards.
为了帮助你创建高度类型安全的应用,Prisma Client 提供了一组可利用输入和输出类型的类型实用程序。这些类型是完全动态的,这意味着它们适应任何给定的模型和模式。你可以使用它们来改善项目的自动补齐和开发者体验。
¥To help you create highly type-safe applications, Prisma Client provides a set of type utilities that tap into input and output types. These types are fully dynamic, which means that they adapt to any given model and schema. You can use them to improve the auto-completion and developer experience of your projects.
这在 验证输入 和 共享 Prisma 客户端扩展 中特别有用。
¥This is especially useful in validating inputs and shared Prisma Client extensions.
Prisma 客户端中提供以下类型实用程序:
¥The following type utilities are available in Prisma Client:
-
Exact<Input, Shape>
:在Input
上强制执行严格的类型安全。Exact
确保泛型类型Input
严格符合你在Shape
中指定的类型。它 narrowsInput
到最精确的类型。¥
Exact<Input, Shape>
: Enforces strict type safety onInput
.Exact
makes sure that a generic typeInput
strictly complies with the type that you specify inShape
. It narrowsInput
down to the most precise types. -
Args<Type, Operation>
:检索任何给定模型和操作的输入参数。这对于想要执行以下操作的扩展作者特别有用:¥
Args<Type, Operation>
: Retrieves the input arguments for any given model and operation. This is particularly useful for extension authors who want to do the following:-
重用现有类型来扩展或修改它们。
¥Re-use existing types to extend or modify them.
-
受益于与现有操作相同的自动补齐体验。
¥Benefit from the same auto-completion experience as on existing operations.
-
-
Result<Type, Arguments, Operation>
:获取输入参数并提供给定模型和操作的结果。你通常会将其与Args
结合使用。与Args
一样,Result
可帮助你重用现有类型来扩展或修改它们。¥
Result<Type, Arguments, Operation>
: Takes the input arguments and provides the result for a given model and operation. You would usually use this in conjunction withArgs
. As withArgs
,Result
helps you to re-use existing types to extend or modify them. -
Payload<Type, Operation>
:检索结果的整个结构,作为给定模型和操作的标量和关系对象。例如,你可以使用它来确定哪些键是类型级别的标量或对象。¥
Payload<Type, Operation>
: Retrieves the entire structure of the result, as scalars and relations objects for a given model and operation. For example, you can use this to determine which keys are scalars or objects at a type level.
例如,以下是强制函数参数与传递给 post.create
的参数相匹配的快速方法:
¥As an example, here's a quick way you can enforce that the arguments to a function matches what you will pass to a 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`