Advanced type safety
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.
Note: If you're interested in advanced type safety topics with Prisma, be sure to check out this blog post about improving your Prisma workflows with the new TypeScript
satisfies
keyword.
Importing generated types
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' objectconst userEmail: Prisma.UserSelect = {email: true,}// Use select objectconst createUser = await prisma.user.create({data: {email: 'bob@prisma.io',},select: userEmail,})
What are generated types?
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
.
For example, select
accepts an object of type UserSelect
. Its object properties match those that are supported by select
statements according to the model.
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 resulting schema model.
type Prisma.UserSelect = {id?: boolean | undefined;email?: boolean | undefined;name?: boolean | undefined;posts?: boolean | Prisma.PostFindManyArgs | undefined;profile?: boolean | Prisma.ProfileArgs | undefined;}
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 = 37const myName: string = 'Rich'
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.
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 @uniquename String?posts Post[]profile Profile?}
import { Prisma } from '@prisma/client'const userEmail: Prisma.UserSelect = {email: true,}// properties available on the typed objectuserEmail.iduserEmail.emailuserEmail.nameuserEmail.postsuserEmail.profile
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 objectuserPosts.postsuserPosts.profile
See the model query options reference for more information about the different types available.