Leverage Prisma's auto-generated types as the input type for functions

Exploring the capabilities of Prisma ORM has led me to experiment with creating models and generating the PrismaClient. Initially, I thought it would be possible to utilize the generated types for variables and response types, but that doesn't seem to be the case.

...

model Invite {
  id        Int        @id @default(autoincrement())
  gender    Gender
  firstName String     @map("first_name")
  lastName  String     @map("last_name")
  language  Language
  email     String     @unique
  token     String     @unique

  roleId Int  @map("role_id")
  role   Role @relation(fields: [roleId], references: [id])

  organisationId Int          @map("organisation_id")
  organisation   Organisation @relation(fields: [organisationId], references: [id])

  updatedAt DateTime @updatedAt @map("updated_at")
  createdAt DateTime @default(now()) @map("created_at")

  @@map("invites")
}

...

The Invite model above includes relationships with the organisation and role models. In an invite service file, I'm preparing all the necessary input to create a new invite.

import { Request, Response, NextFunction } from 'express';
import roleRepository from '../repositories/role.repository';
import organisationRepository from '../repositories/organisation.repository';
import generateToken from '../utils/helpers/generateToken';
import inviteRepository from '../repositories/invite.repository';

const createInvite = async (req: Request, res: Response) => {
    const { body } = await validateInput(req);
    const { gender, firstName, lastName, email, language, roleId, organisationId } = body;

    const role = roleRepository.findRoleById(roleId);

    if (!role) {
        throw new Error('Role does not exist');
    }

    const organisation = organisationRepository.findOrganisationById(organisationId);

    if (!organisation) {
        throw new Error('Organisation does not exist');
    }

    const token = generateToken();

    const invite = inviteRepository.createInvite({
        gender,
        firstName,
        lastName,
        email,
        language,
        role: role,
        organisation: organisation,
        token,
    });

    await mailService.sendInviteEmail(invite);

    res.status(201).json({
        message: 'Invite created successfully',
    });
};

Within the createInvite function in the inviteRepository file, I attempt to use a generated Prisma type called InviteCreateInput.

const createInvite = async (inviteData: Prisma.InviteCreateInput): Promise<Invite> => {
    return db.invite.create({
        data: {
            gender: inviteData.gender,
            firstName: inviteData.firstName,
            lastName: inviteData.lastName,
            language: inviteData.language,
            email: inviteData.email,
            token: inviteData.token,
            role: {
                connect: {
                    id: inviteData.role
                }
            },
            organisation: {
                connect: {
                    id: inviteData.organisation,
                }
            }
        },
    });
};

Prisma suggests using this 'safe' Input approach, however, the InviteCreateInput type structure is not fitting for my needs.

  export type InviteCreateInput = {
    gender: Gender
    firstName: string
    lastName: string
    language: string
    email: string
    token: string
    updatedAt?: Date | string
    createdAt?: Date | string
    role: RoleCreateNestedOneWithoutInviteInput
    organisation: OrganisationCreateNestedOneWithoutInvitesInput
  }

The

RoleCreateNestedOneWithoutInviteInput
looks like this:

  export type RoleCreateNestedOneWithoutInviteInput = {
    create?: XOR<RoleCreateWithoutInviteInput, RoleUncheckedCreateWithoutInviteInput>
    connectOrCreate?: RoleCreateOrConnectWithoutInviteInput
    connect?: RoleWhereUniqueInput
  }

Considering the limitations of the Prisma generated types, I question whether to continue using them as function parameter types or to create custom types instead.

Answer №1

Prisma suggests that their approach is "safer" because they assume you might overlook checking for the roleId and organisationId (as done with findRoleById and findOrganisationById).

To optimize performance, consider eliminating the extra queries - findRoleById and findOrganisationById, and modify your middleware as follows:

const createInvite = async (req: Request, res: Response) => {
  const { body } = await validateInput(req);
  const { gender, firstName, lastName, email, language, roleId, organisationId } = body;

  const token = generateToken();

  try {
    const invite = await inviteRepository.createInvite({
      gender,
      firstName,
      lastName,
      email,
      language,
      token,
      role: {
        connect: {
          id: roleId,
        },
      },
      organisation: {
        connect: {
          id: organisationId,
        },
      },
    });
  } catch (error) {
    // handle errors if organisationId or roleId do not exist
    // use next(Error) or similar method
  }

  await mailService.sendInviteEmail(invite);

  res.status(201).json({
    message: 'Invite created successfully',
  });
};

You can also streamline your createInvite function:

const createInvite = async (data: Prisma.InviteCreateInput): Promise<Invite> => {
  return db.invite.create({
    data,
  });
};

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

Unable to access current props within useEffect block

When I use useEffect with the parameter props.quizStep, my function fn (which is a keydown event listener) is unable to access the current value of props.quizStep. I'm puzzled as to why it's not working properly. Can you help me understand? Bel ...

Exploring the power of a mapped type within a tuple

Can TypeScript ensure the validity of key-value tuples in this function? function arrayToObject(array, mapper) { const result = {}; for(const item of array) { const [key, value] = mapper(item); result[key] = value; } return ...

Is the input URL modified by the Angular HttpClientModule's GET request?

I am currently using an Angular service to make calls to a Node.js server in order to fetch data. Here is a snippet of my code: constructor(private http: HttpClient){ } getPersonData(): Observable<person[]> { //return this.http.get<person ...

Guide on merging paths in distinct modules within an Angular project

I am looking to merge two sets of routes from different modules in my application. The first module is located at: ./app-routing.module.ts import {NgModule} from '@angular/core'; import {Routes, RouterModule} from '@angular/router'; i ...

Utilizing Typescript in tandem with an external library through es6 modules

Is there a recommended method for incorporating Typescript with non-module libraries like PixiJS and SortableJS without using webpacker? I'm looking to utilize es6 modules but want to avoid cumbersome solutions. What would be the best approach in this ...

Unlock the Power of Typography in React with Material UI Styled Components

Exploring the world of material UI is a new experience for me. I am currently in the process of creating a styled component using Typography. Below is what I have attempted so far: import styled from 'styled-components'; import { FormGroup, ...

Why isn't the page showing up on my nextjs site?

I've encountered an issue while developing a web app using nextjs. The sign_up component in the pages directory is not rendering and shows up as a blank page. After investigating with Chrome extension, I found this warning message: Unhandled Runtime ...

How come TypeScript does not generate an error when attempting to import a default export that does not exist?

As I work on converting my code from non-TypeScript CommonJS files to TypeScript ES6 modules, I encountered an issue with the import statements. Specifically, I needed to use import * as x instead of import x: The original snippet looked like this: const ...

Automatically pass on parameters from a universal function

If I have an object with functions that return numbers: const obj = { foo() { return 1; } bar() { return 2; } baz(num: number) { return num; } } The expected output of typeof obj would be: { foo: () => number; bar: () => number; baz ...

A simple way to automatically fill an input field with a mask when clicking in Angular 2

When a user clicks on this span, the following action is triggered: <span data-content="15" #Fast15 (click)="enterFastTime(Fast15)" class="quick-time">15mins</span> Users can also manually input a date in the following input field. If they ...

Utilize the CSS class or variable within an Angular TypeScript file for enhanced styling and functionality

Is it possible to utilize the scss class or variable in a typescript file? scss .thisIsGreen { color: green; } .thisIsBlue { color: blue; } Alternatively, you can use $thisIsGreen { color: green; } $thisIsBlue { color: blue; } Now, I want to ...

Properly incorporating a git+https dependency

I'm facing an issue while trying to utilize a git+https dependency from Github to create a TypeScript library. I've minimized it to a single file for illustration purposes, but it still doesn't work. Interestingly, using a file dependency fu ...

Issue encountered on server using next.js - FetchError: failed to process request for https://jsonkeeper.com/b/4G1G

Struggling to fetch JSON data from a link and destructure it for use on the website. I have a getStaticProps export function that extracts the data and I want to pass it into my default Home function to iterate through it. I have come across information ab ...

What is the best way to implement function chaining in TypeScript?

I'm interested in implementing function chaining in typescript. Let's consider a sample class: export class NumberOperator { private num; constructor(initialNum) { this.num = initialNum; } public add(inc = 1) { this.num += inc ...

The TypeScript find() method on an array are showing an error message that says, "There is no overload that matches this call

Issue Description I encountered a problem while using TypeScript's find() method for an array. Whenever I input a value, it does not work properly and displays an error message stating, "No overload matches this call". Code Snippet addOption(event: ...

The index access type cannot be used with T[Key extends keyof T]

My work frequently involves arrays structured like this: [ {key1: val1, key2: value2, key3: val3}, {key1: val1, key2: value2, key3: val3}, {key1: val1, key2: value2, key3: val3}] and I often need to convert them into a dictionary/map format, for example: ...

Navigating the proper utilization of exports and subpaths in package.json with TypeScript

As a newbie in creating npm packages using TypeScript, I've encountered some issues that I believe stem from misinterpreting the documentation. Currently, I am working with Node 16.16.0 and npm 8.13.2. Here is the structure of my project: src/ ├─ ...

`In TypeScript Angular, encountering challenges with accessing object properties`

My TypeScript object looks like this const playlist: { tracks: Array<Track> } = { tracks: new Array<Track>() }; This is the Track interface I am working with interface Track { title?: string; album?: string; artists?: string; duration? ...

When converting to TypeScript, the error 'express.Router() is not defined' may

Currently, I am in the process of converting my express nodejs project from JavaScript to TypeScript. One of the changes I've made is renaming the file extension and updating 'var' to 'import' for "require()". However, there seems ...

Creating a sophisticated union type by deriving it from another intricate union type

I have a unique data structure that includes different types and subtypes: type TypeOne = { type: 'type-one', uniqueKey1111: 1, }; type TypeTwo = { type: 'type-two', uniqueKey2222: 2, } type FirstType = { type: 'first&apo ...