get full type on prisma client

When i generate my prisma client with prisma generate, i got an index.d.ts with all types from my database. But the probleme is that all type are "single" and there is no relations. When i query something like

prisma.users.findMany({
            [... ]
            include: {
                cars: {
                  [...]
                }}});

prisma type the response dynamically with the right type

users & {
        cars: cars & {
           [...]
        };
    }

So everything work well and I have the auto completion, except if I want to pass this variable to another method, I would like to type the parameters, so I have to create my own type used as method parameter.

type prismaUsers = users & {
        cars?: cars & {
           [...]
        };
    }

But I'm asking if there is a way to get the "full" type from prisma to avoid me to create all "full" types with optionals sub-elements like I did for the user example. Or maybe i'm doing wrong and there is another way to do?


Solution 1:

You can use the Prisma Validator API along with some typescript features to generate types for your query.

For the findMany example you mentioned

import { Prisma } from '@prisma/client'

// 1. Define a User type that includes the "cars" relation. 
const userWithCars = Prisma.validator<Prisma.UserArgs>()({
    include: { cars: true },
})

// 2: This type will include many users and all their cars
type UserWithCars = Prisma.UserGetPayload<typeof userWithCars>[]

If you simply want to automatically infer the return type of a prisma query wrapped in a function, you can use PromiseReturnType.

For example:

import { Prisma } from '@prisma/client'

async function getUsersWithCars() {
  const users = await prisma.user.findMany({ include: { cars: true } });
  return users;
}

type UsersWithCars = Prisma.PromiseReturnType<typeof getUsersWithCars>

You can read more about this in the Operating against partial structures of your model types concept guide in the Prisma docs.

Solution 2:

An alternate method (my preferrence) to get the "full" type, or the model with all of its possible relations, is to use the GetPayload version of your model type. The type is a generic that can receive the same object you pass to your query.

import { PrismaClient, Prisma } from "@prisma/client";

const prisma = new PrismaClient();

type UserWithCars = Prisma.UserGetPayload<{
  include: {
    cars: true;
  }
}>

const usersWithCars = await prisma.user.findMany({
  include: {
    cars: true,
  }
});

As your query grows more complex, you may want to abstract it and ensure that it is strongly typed.

import { Prisma, PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const userInclude = Prisma.validator<Prisma.UserInclude>()({
  cars: true,
});

type UserWithCars = Prisma.UserGetPayload<{
  include: typeof userInclude;
}>;

const usersWithCars = await prisma.user.findMany({
  include: userInclude,
});

Solution 3:

Most easily you can define the corresponding type with typeof:

myQuery = await prisma.users.findMany({
            [... ]
            include: {
                cars: {
                  [...]
                }}});
type prismaUsers = typeof myQuery

Or if you decide to wrap your query inside a function, you may let TypeScript infer the return type for you:

function queryUserWithCar(...) {
  return prisma.users.findMany({
            [... ]
            include: {
                cars: {
                  [...]
                }}});
}

and then extract the function's return type:

type prismaUser = ReturnType<typeof queryUserWithCar> extends Promise<infer T> ? T : never