The specific type of selection return type in Prisma is restricted

My Prisma schema is structured like this:

model Sample {
    id        String   @id @default(cuid())
    createdOn DateTime @default(now())
    category  String
}

category should STRICTLY belong to one of these options:

const Categories = [
  "alphaCategory",
  "betaCategory",
  "gammaCategory",
  ...
] as const;

As I am using Prisma with an MSSQL database, I cannot utilize Prisma's enums. To ensure accuracy during inserts, I rely on the satisfies operator for validity.

category: "betaCategory" satisfies ClassificationType,

This method works adequately well for me, though it's not foolproof. However, issues arise when dealing with select statements because the return type of the category field remains as string, which is too generic.

One idea I had was to customize the Prisma client, but my current approach has not yielded the desired outcome:

type ClassificationType = (typeof Categories)[number];
const custom = prisma.$extends({
  name: "sample",
  query: {
    example: {
      // narrow down the return type to make the field `category` of type ClassificationType
      async findMany({ model, args, operation, query }) {
        const queryResult = await query(args);
        return queryResult.map((item) => {
          return {
            ...item,
            category: item.category as ClassificationType,
          };
        });
      },
    },
  },
});

However, the return type still remains as string.

Answer №1

Disclaimer

The solution provided may not be the most elegant one, but it is functional. It involves a considerable amount of customization using prisma. Each type will be explained in detail to achieve the desired result.


First Step

To enable specific strings as literal types through intellisense, a custom type needs to be created that allows any string while providing intellisense for selected strings. Below is an example implementation:

type StringWithAutocomplete<T> =
  | T
  | Omit<string & Record<never, never>, keyof string>;

type UserNames = "John" | "Bobby" | "Jack" | "Tony";

let a: StringWithAutocomplete<UserNames> = "something else";
let b: StringWithAutocomplete<UserNames> = "Bobby";

This approach provides intellisense for specified strings while allowing assignment of any string to a variable.


Building out types for method: findManyCustom

In order to create the findManyCustom method, the types from the findMany operation on our model need to be examined. The example below uses Prisma's official docs' quickstart user and post models:

// Models definition
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int
}

The findManyCustom method will provide intellisense for the User's name field by customizing the input parameters. This involves creating custom typings based on the existing Prisma definitions.


Putting it all together

An encapsulated code block combining all the defined types and implementations for the findManyCustom method can be seen below:

// Code snippet with all custom types and method implementation
// Implementation for findManyCustom method
const prisma = new PrismaClient();

prisma.user.findManyCustom<Prisma.UserFindManyArgs<Types.Extensions.DefaultArgs>> = (args) => {
  return prisma.user.findMany(args);
};

With this setup, the findManyCustom method on the User model will now have intellisense for the name field. Success!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sending data between components in Angular can be achieved by using various methods. One common approach is to utilize

I am encountering an issue with a component named customers.component Below is the code from the customers.component.ts file: @Component({ selector: 'app-customer', templateUrl: './customer.component.html', styleUrls: ['./cu ...

The reset function in Angular's template-driven form does not seem to be functioning properly when implemented using a component

Form Template Example <form #contactFormTemplate = "ngForm" (ngSubmit)="submitContactForm()"> <input type="text" class="form-control" name="name" [(ngModel)]="formData.name" ...

Troubleshooting issues with injecting MongoDB connection in NestJS as it fails to function

I am attempting to establish a basic connection with my localhost: Instead of using Models or Schemas due to the dynamic nature of the data structure, I prefer to work with the native Mongoose Connection app.module.ts import { Module } from '@nestjs ...

Can the ngx-chips library be used to alter the language of chips?

Currently, I am working with the ngx-chips library and encountering a particular issue. Here is an image representation of the problem: https://i.sstatic.net/GL3Fd.png The challenge I am facing involves updating the language of the chips based on the sele ...

getStaticProps will not return any data

I'm experiencing an issue with my getStaticProps where only one of the two db queries is returning correct data while the other returns null. What could be causing this problem? const Dash = (props) => { const config = props.config; useEffect(() ...

The Angular firestore is showing an error stating that the property 'toDate' is not found in the 'Date' type

I am currently working on converting a timestamp object from Firestore to a Date object in TypeScript by utilizing the toDate() method. import { AngularFirestore } from '@angular/fire/firestore'; ... constructor(private database?: AngularFirestor ...

The lazy loading feature in Angular 12 is not functioning correctly for path modules

My application has a jobs module with various components, and I'm trying to lazy load it. However, I've encountered an issue where accessing the module through the full path http://localhost:4200/job/artist doesn't work, but accessing it thr ...

Combining Typescript and React to create a conditional callback prop type depending on whether an optional prop is

In my react component, I have the option to pass an optional prop called isSingle (boolean) and a required prop called onSelect (callback). If the isSingle prop is used, I want the callback to have a different signature. type CustomProps<T> = { ...

Jest assertions encountering type errors due to Cypress

After using react-testing-library and @testing-library/jest-dom/extend-expect, I decided to install Cypress. However, I now face Typescript errors on all my jest matchers: Property 'toEqual' doesn't exist on type 'Assertion'. Did ...

Executing multiple queries in a node.js transaction with Sequelize using an array

I am looking to include the updates on the clothingModel inside a transaction, with the condition that if it successfully commits, then update the reservationModel. This is the snippet of code I am attempting to refactor using sequelize.transaction tr ...

A step-by-step guide on configuring data for aria's autocomplete feature

Currently, I am implementing aria autocomplete and facing an issue while trying to populate data from the server into the selection of aria autocomplete. I have tried setting the selected property of the aria autocomplete object, but it doesn't seem t ...

JavaScript: Navigating function passing between multiple React components

I'm currently working on a React Native application utilizing TypeScript. In my project, there is a component named EmotionsRater that can accept two types: either Emotion or Need. It should also be able to receive a function of type rateNeed or rate ...

Do we really need Renderer2 in Angular?

Angular utilizes the Renderer2 class to manipulate our view, acting as a protective shield between Angular and the DOM, making it possible for us to modify elements without directly interacting with the DOM ourselves. ElementRef provides another way to al ...

Is there a way to automatically extend my content to fill the space on the page below the Material UI AppBar?

I am currently using React and Material UI React to develop my application. My goal is to implement the AppBar component with content underneath, without causing the entire page to scroll. I want the content to occupy the maximum remaining height and the f ...

Determining the height of dynamically rendered child elements in a React application

Looking for a way to dynamically adjust the heights of elements based on other element heights? Struggling with getting references to the "source" objects without ending up in an infinite loop? Here's what I've attempted so far. TimelineData cons ...

Error encountered in Angular 7.2.0: Attempting to assign a value of type 'string' to a variable of type 'RunGuardsAndResolvers' is not allowed

Encountering an issue with Angular compiler-cli v.7.2.0: Error message: Types of property 'runGuardsAndResolvers' are incompatible. Type 'string' is not assignable to type 'RunGuardsAndResolvers' This error occurs when try ...

Guide on integrating an element into a different element in a Vue 3 Tree Viewer

In my current setup, I've implemented a TreeView component that holds a tree. Each tree entry includes Children with their own unique label, perm, and further children. Take a look at an example of the tree: App.vue let tree = ref({ label: 'o ...

Trouble with updating a variable within a loop in Cypress

During my experience with writing Cypress tests, I came across an issue that is preventing me from updating a specific variable. The goal of my test is to run a loop and update the questionId variable within each iteration for making API queries. However, ...

Adding a fresh element and removing the initial item from a collection of Objects in JavaScript

I'm working on creating an array of objects that always has a length of five. I want to push five objects initially, and once the array reaches a length of five, I need to pop the first object and push a new object onto the same array. This process sh ...

After defining the NEXTAUTH_URL and NEXTAUTH_SECRET variables, the getServerSession(authOptions) function in NextJS is returning null

I've been attempting to set up OAuth with the Google provider for my Next.js 13 web application. Unfortunately, I'm encountering an issue where getServerSession(authOptions) is returning null. Despite trying various solutions such as setting NEXT ...