P
Prisma5mo ago
Dhcdec

How to properly type return and include types for my function

import { Prisma, PrismaClient } from '@composabl/database'; type ModelName = Prisma.ModelName; type ModelDelegate<N extends ModelName> = PrismaClient[Uncapitalize<N>]; type FindManyArgs<N extends ModelName> = Prisma.TypeMap['model'][N]['operations']['findMany']['args']; type WhereInput<N extends ModelName> = NonNullable<FindManyArgs<N>['where']>; type OrderByInput<N extends ModelName> = NonNullable<FindManyArgs<N>['orderBy']>; export interface QueryOptions<TOrderBy,
TModel extends Prisma.ModelName> {
single?: boolean;
take?: number;
orderBy?: TOrderBy;
include?: TModel;
}

export const queryByCriteria = async<N extends ModelName>(
model: ModelDelegate<N>,
criteria: WhereInput<N>,
options: QueryOptions<OrderByInput<N>>,
): Promise<ModelDelegate<N>> => {
const { single = false, ...queryOptions } = options;
const method = single ? 'findFirst' : 'findMany';
// @ts-expect-error: TypeScript cannot guarantee method compatibility across all models
return model[method]({
where: criteria,
...queryOptions,
});
};
TModel extends Prisma.ModelName> {
single?: boolean;
take?: number;
orderBy?: TOrderBy;
include?: TModel;
}

export const queryByCriteria = async<N extends ModelName>(
model: ModelDelegate<N>,
criteria: WhereInput<N>,
options: QueryOptions<OrderByInput<N>>,
): Promise<ModelDelegate<N>> => {
const { single = false, ...queryOptions } = options;
const method = single ? 'findFirst' : 'findMany';
// @ts-expect-error: TypeScript cannot guarantee method compatibility across all models
return model[method]({
where: criteria,
...queryOptions,
});
};
1 Reply
Prisma AI Help
Prisma AI Help5mo ago
You opted for speed from this bot. Let's conjure up an answer right now! To properly type the return and include types for your generic Prisma query function, you need to leverage Prisma’s type utilities to ensure that the return type dynamically reflects the include or select options passed in the arguments. This is a common challenge, and the knowledge sources show several approaches and their limitations. Key Points - Using just the delegate’s return type (e.g., ModelDelegate<N>) is not sufficient, as it does not account for dynamic include or select options—this leads to incorrect or overly broad types [source]. - The recommended approach is to use Prisma’s GetPayload utility or, for function arguments, SelectSubset to infer the correct return type based on the arguments [source], [source]. Example Solution Here’s how you can type your function so that the return type matches the include or select options:
import { Prisma, PrismaClient } from '@composabl/database';

type ModelName = Prisma.ModelName;
type ModelDelegate<N extends ModelName> = PrismaClient[Uncapitalize<N>];
type FindManyArgs<N extends ModelName> = Prisma.TypeMap['model'][N]['operations']['findMany']['args'];

export const queryByCriteria = async <
N extends ModelName,
TArgs extends FindManyArgs<N>
>(
model: ModelDelegate<N>,
args: TArgs,
single: boolean = false
): Promise<
TArgs extends { include: any }
? Prisma.TypeMap['model'][N]['payload']['include'] // This is illustrative; use GetPayload if available
: TArgs extends { select: any }
? Prisma.TypeMap['model'][N]['payload']['select']
: Prisma.TypeMap['model'][N]['payload']['default']
> => {
const method = single ? 'findFirst' : 'findMany';
// @ts-expect-error: TypeScript cannot guarantee method compatibility across all models
return model[method](args);
};
import { Prisma, PrismaClient } from '@composabl/database';

type ModelName = Prisma.ModelName;
type ModelDelegate<N extends ModelName> = PrismaClient[Uncapitalize<N>];
type FindManyArgs<N extends ModelName> = Prisma.TypeMap['model'][N]['operations']['findMany']['args'];

export const queryByCriteria = async <
N extends ModelName,
TArgs extends FindManyArgs<N>
>(
model: ModelDelegate<N>,
args: TArgs,
single: boolean = false
): Promise<
TArgs extends { include: any }
? Prisma.TypeMap['model'][N]['payload']['include'] // This is illustrative; use GetPayload if available
: TArgs extends { select: any }
? Prisma.TypeMap['model'][N]['payload']['select']
: Prisma.TypeMap['model'][N]['payload']['default']
> => {
const method = single ? 'findFirst' : 'findMany';
// @ts-expect-error: TypeScript cannot guarantee method compatibility across all models
return model[method](args);
};
Note: The actual type for the return value should use Prisma.GetPayload<TArgs> if available for your Prisma version, or the equivalent from your generated types. This ensures the return type matches the shape dictated by select or include [source], [source]. If you need a concrete example for a specific model, see the wrapper function example using SelectSubset and GetPayload. --- Summary:
Use Prisma’s type utilities (GetPayload, SelectSubset) to type your function’s return value based on the query arguments, ensuring correct type inference for include/select. The knowledge sources do not provide a single drop-in type, but the above pattern is the recommended approach. ✅ Great, thanks for letting us know that this solved your question!

Did you find this page helpful?