1

I'm working with Prisma to make a generic repository object. Here's my current interface (which the base repository implements) which works:

import { Log as LogSchema, Prisma, User as UserSchema } from "@prisma/client";
import type { CamelCase } from "type-fest";


type PrismaSchema = UserSchema | LogSchema; // I currently have to define all schemas schema.prisma here
type NonWriteable = "updatedAt" | "createdAt"; // I also have to explicitly define fields which should never be writeable
type WriteableSchemaWithId<Schema> = Omit<Schema, NonWriteable>;
type WriteableSchema<Schema> = Omit<WriteableSchemaWithId<Schema>, "id">;

interface IBaseRepository<
  Key extends CamelCase<Prisma.ModelName>,
  Schema extends PrismaSchema
> {
  create: (parameters: { [key in Key]: WriteableSchema<Schema> }) => Promise<{
    id: number;
  }>;

  // ... Other methods
}

However, in the type of argument to the create method are slightly incorrect. I'd really be like to using the Prisma-generated types instead of the type of the schema. For example, the Prisma client exports UserCreateArgs which defines what can be passed to prisma.user.create({ data: ... }).

Then I'd have to do this for all actions, for all schemas. Now, this isn't a problem currently because there are only two models with no relations to each other. However, I'm expecting this implementation to become brittle (and cumbersome) with a more complex database schema.

Instead, I was looking for something like:

import { Prisma } from "@prisma/client";
import type { PascalCase } from "type-fest";

type NamespaceKey<
  Model extends Prisma.ModelName,
  Action extends Prisma.PrismaAction
> = `${Capitalize<Model>}${PascalCase<Action>}Args`;

type ActionArgs<
  Model extends Prisma.ModelName,
  Action extends Prisma.PrismaAction
> = typeof Prisma[NamespaceKey<Model, Action>];

Where NamespaceKey turns User into e.g., UserCreateArgs which should be imported from the Prisma namespace.

But I get an error saying NamespaceKey cannot be used to index typeof Prisma.

Is there a way to get what I'm looking for?


Edit:

The problem seems to revolve around the inability to string-index types in a namespace.

For example, Prisma["ModelName"] works as the following is exported:

export const ModelName: {
  User: 'User',
  Log: 'Log'
};

Along with the type:

export type ModelName = (typeof ModelName)[keyof typeof ModelName]

However, Prisma["UserCreateArgs"] does not seem to exist since UserCreateArgs is a type.

So, it seems like it is not possible to string-index the types defined in a namespace. If this were possible, one would assume what I have already would work.

Inkblot
  • 708
  • 2
  • 8
  • 19
  • You might be interested in [this](https://stackoverflow.com/questions/72075773/how-to-infer-types-from-an-imported-file-in-typescript/72261666#72261666) question. – kelsny May 22 '22 at 13:18
  • @catgirlkelly Thanks for the suggestion but I was looking for a way to not have to explicitly define model schemas. If there's no way to do that I guess the linked solution is probably the next best bet – Inkblot May 22 '22 at 13:56
  • If only we had ``Eval<`${Capitalize}${PascalCase}Args`>``... – kelsny May 22 '22 at 14:02
  • @catgirlkelly I think the main issue is that I'm trying to access a namespace like it's an object ... which does not seem to be possible? – Inkblot May 22 '22 at 14:35

0 Answers0