P
Prisma5mo ago
Dhcdec

Not sure what types to use to correctly restrict my generics

I am looking to do something like this wthe criteria and options arguments so they are restricted depending on the model i pass in. The current types are not real.
export interface QueryOptions<TOrderBy> {
single?: boolean;
take?: number;
orderBy?: TOrderBy;
}

export const queryByCriteria = async <TModel extends Prisma.TableDelegate>(
model: TModel,
criteria: Prisma.WhereInput<TModel>,
options: QueryOptions<Prisma.OrderByWithRelationInput<TModel>>,
): Promise<any> => {
return withDatabaseError(async () => {
const { single = false, ...queryOptions } = options;
const method = single ? 'findFirst' : 'findMany';

return model[method]({
where: criteria,
...queryOptions
});
});
};
export interface QueryOptions<TOrderBy> {
single?: boolean;
take?: number;
orderBy?: TOrderBy;
}

export const queryByCriteria = async <TModel extends Prisma.TableDelegate>(
model: TModel,
criteria: Prisma.WhereInput<TModel>,
options: QueryOptions<Prisma.OrderByWithRelationInput<TModel>>,
): Promise<any> => {
return withDatabaseError(async () => {
const { single = false, ...queryOptions } = options;
const method = single ? 'findFirst' : 'findMany';

return model[method]({
where: criteria,
...queryOptions
});
});
};
3 Replies
Prisma AI Help
Prisma AI Help5mo ago
You selected the bot's instantaneous insights. Let me compile your answer right away! To achieve type-safe generics for your queryByCriteria function, you need to leverage Prisma's type utilities, specifically Prisma.Args and Prisma.Result, or use the types exposed in the generated Prisma client. However, Prisma does not provide a direct WhereInput<TModel> or OrderByWithRelationInput<TModel> generic out of the box. Instead, you can extract these types using the Prisma type map or the Args utility. Here’s a pattern based on the knowledge sources:
import { PrismaClient, Prisma } from '@prisma/client';

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> {
single?: boolean;
take?: number;
orderBy?: TOrderBy;
}

export const queryByCriteria = async <
N extends ModelName
>(
model: ModelDelegate<N>,
criteria: WhereInput<N>,
options: QueryOptions<OrderByInput<N>>,
): Promise<any> => {
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,
});
};
import { PrismaClient, Prisma } from '@prisma/client';

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> {
single?: boolean;
take?: number;
orderBy?: TOrderBy;
}

export const queryByCriteria = async <
N extends ModelName
>(
model: ModelDelegate<N>,
criteria: WhereInput<N>,
options: QueryOptions<OrderByInput<N>>,
): Promise<any> => {
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,
});
};
Notes: - This approach uses the Prisma TypeMap to extract the correct types for where and orderBy based on the model name, as shown in this solution. - TypeScript may still require a type assertion or @ts-expect-error because the method signatures differ slightly between models, which is a known limitation (see discussion). - There is no official Prisma.TableDelegate or Prisma.WhereInput<TModel> t ype, so you must use the type map workaround. This is the most type-safe approach available with current Prisma versions, but some type assertions may be unavoidable due to TypeScript's limitations with method signatures across model delegates Type utilities docs.
Dhcdec
DhcdecOP5mo ago
Any way to have this return anythin but any?
Prisma AI Help
Prisma AI Help5mo ago
✅ Great, thanks for letting us know that this solved your question!

Did you find this page helpful?