Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types mismatch between the generated zod types and the prisma client types #98

Open
atanaskanchev opened this issue Mar 8, 2023 · 9 comments
Labels
pending Waiting on a response or on some dependency update

Comments

@atanaskanchev
Copy link

atanaskanchev commented Mar 8, 2023

zod-prisma-types generates a schema for a field missing in the prisma generated types

"@prisma/client": "4.11.0",
 "zod-prisma-types": "2.4.0"

The Prisma schema

generator client {
    provider = "prisma-client-js"
}

generator zod {
    provider           = "zod-prisma-types"
}

datasource db {
    provider = "postgresql"
    url      = env("DATABASE_URL")
}

model Account {
    id           String    @id @default(cuid())
    createdAt    DateTime  @default(now())
    updatedAt    DateTime? @updatedAt
    countryCode  String?
    countryName  String?
    currencyCode String    @default("USD")
    isOnboarded  Boolean   @default(false)
    user         User[]
    contact      Contact[]
}

model User {
    id        String    @id @default(cuid())
    createdAt DateTime  @default(now())
    updatedAt DateTime? @updatedAt
    email     String    @unique
    name      String?
    language  String    @default("en")
    locale    String    @default("en-US")
    contact   Contact[]
    role      Role[]    @default([ADMIN])
    account   Account   @relation(fields: [accountId], references: [id])
    accountId String
}

enum Role {
    ADMIN
}

model Contact {
    id           String      @id @default(cuid())
    createdAt    DateTime    @default(now())
    updatedAt    DateTime    @updatedAt
    contactType  ContactType @default(OTHER)
    firstName    String
    lastName     String
    businessName String?
    displayName  String?
    isBusiness   Boolean     @default(false)
    phone        Phone[]
    email        Email[]
    address      Address[]
    user         User[]
    account      Account     @relation(fields: [accountId], references: [id])
    accountId    String
}

enum ContactType {
    OTHER
}

model Phone {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    number    String
    isPrimary Boolean  @default(false)
    contact   Contact  @relation(fields: [contactId], references: [id])
    contactId String
}

model Email {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    email     String
    isPrimary Boolean  @default(false)
    contact   Contact  @relation(fields: [contactId], references: [id])
    contactId String
}

model Address {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    line1     String
    line2     String?
    city      String
    state     String?
    region    String?
    zip       String
    country   String
    formatted String?
    contact   Contact  @relation(fields: [contactId], references: [id])
    contactId String
}

the generated zod type having an error

export const ContactCreateWithoutUserInputSchema: z.ZodType<Prisma.ContactCreateWithoutUserInput> = z.object({
  id: z.string().optional(),
  createdAt: z.coerce.date().optional(),
  updatedAt: z.coerce.date().optional(),
  contactType: z.lazy(() => ContactTypeSchema).optional(),
  firstName: z.string(),
  lastName: z.string(),
  businessName: z.string().optional().nullable(),
  displayName: z.string().optional().nullable(),
  isBusiness: z.boolean().optional(),
  phone: z.lazy(() => PhoneCreateNestedManyWithoutContactInputSchema).optional(),
  email: z.lazy(() => EmailCreateNestedManyWithoutContactInputSchema).optional(),
  address: z.lazy(() => AddressCreateNestedManyWithoutContactInputSchema).optional(),
  account: z.lazy(() => AccountCreateNestedOneWithoutContactInputSchema),
}).strict();

export const ContactUncheckedCreateWithoutUserInputSchema: z.ZodType<Prisma.ContactUncheckedCreateWithoutUserInput> = z.object({
  id: z.string().optional(),
  createdAt: z.coerce.date().optional(),
  updatedAt: z.coerce.date().optional(),
  contactType: z.lazy(() => ContactTypeSchema).optional(),
  firstName: z.string(),
  lastName: z.string(),
  businessName: z.string().optional().nullable(),
  displayName: z.string().optional().nullable(),
  isBusiness: z.boolean().optional(),
  accountId: z.string(),
  phone: z.lazy(() => PhoneUncheckedCreateNestedManyWithoutContactInputSchema).optional(),
  email: z.lazy(() => EmailUncheckedCreateNestedManyWithoutContactInputSchema).optional(),
  address: z.lazy(() => AddressUncheckedCreateNestedManyWithoutContactInputSchema).optional(),
}).strict();

export const ContactCreateOrConnectWithoutUserInputSchema: z.ZodType<Prisma.ContactCreateOrConnectWithoutUserInput> = z.object({
  where: z.lazy(() => ContactWhereUniqueInputSchema),
  create: z.union([ z.lazy(() => ContactCreateWithoutUserInputSchema),z.lazy(() => ContactUncheckedCreateWithoutUserInputSchema) ]),
}).strict();

the generated prisma type

  export type ContactCreateWithoutUserInput = {
    id?: string
    createdAt?: Date | string
    updatedAt?: Date | string
    contactType?: ContactType
    firstName: string
    lastName: string
    businessName?: string | null
    displayName?: string | null
    isBusiness?: boolean
    phone?: PhoneCreateNestedManyWithoutContactInput
    email?: EmailCreateNestedManyWithoutContactInput
    address?: AddressCreateNestedManyWithoutContactInput
    account: AccountCreateNestedOneWithoutContactInput
  }

the ts error

       Type 'ContactCreateWithoutUserInput & ContactUncheckedCreateWithoutUserInput' is not assignable to type 'Without<ContactUncheckedCreateWithoutUserInput, ContactCreateWithoutUserInput>'.
            Types of property 'accountId' are incompatible.
              Type 'string' is not assignable to type 'undefined'.ts(2322)`
@chrishoermann
Copy link
Owner

@atanaskanchev thank's for the report. I'm aware of this issue and currently working on a fix for that. This has to do with an updated Prisma XOR type that does not accept a simple union anymore.

@chrishoermann
Copy link
Owner

@atanaskanchev this seems to be a bit of a complex issue. I've started a discussion on the zod page on how this could be resolved.

@njdowdy
Copy link

njdowdy commented Mar 10, 2023

I rolled back Zod to 3.21.1 from 3.21.2 and that's getting me past this issue.

@chrishoermann
Copy link
Owner

Opened an issue in the zod repo: colinhacks/zod#2184

@chrishoermann chrishoermann added the pending Waiting on a response or on some dependency update label Mar 12, 2023
@ianhernandez
Copy link

I tried rolling back but ran into this error:

Property 'coerce' does not exist on type 'typeof import(\"/path/to/project/node_modules/zod/lib/external\")'.

export const UserSchema = z.object({
  id: z.string().cuid(),
  name: z.string().nullable(),
  email: z.string(),
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
})

@artem-alek
Copy link

I rolled back Zod to 3.21.1 from 3.21.2 and that's getting me past this issue.

I was able to get around this as well by rolling back to 3.21.1 from 3.21.4

@chrishoermann
Copy link
Owner

Since there is no movement on the zod issue I thought of a rude override to enable the use of zod version greater than 3.21.1:

The simple solution for now would be to just add a type assertion like:

export const UserCreateInputSchema: z.ZodType<Prisma.UserCreateInput> = z.object({
id: z.string().cuid().optional(),
email: z.string().email({ message: "Invalid email address" }),
name: z.string().min(1).max(100).optional().nullable(),
...
}).strict() as z.ZodType<Prisma.UserCreateInput>;

since the schemas work, as confirmd by using zod 3.21,1 there should be little risk that the behavior breaks when using type assertions. But as mentioned above it feels like a dirty hack that hurts my typesafe heart a little bit and that should actually not be needed.

Any thougths on this? should probably be swichable via generator option and off by default.

samwillis pushed a commit to electric-sql/electric that referenced this issue Dec 11, 2023
This PR fixes the problem where the generated client may contain type
errors for models containing relations.
This is a known problem with Zod and Prisma and is described here:
chrishoermann/zod-prisma-types#98. That issue
also proposes a solution with a dirty type cast:
chrishoermann/zod-prisma-types#98 (comment)
which is implemented in this PR.

This PR removes the need for pinning the version of Zod
(#700).
@barbalex
Copy link

barbalex commented Apr 15, 2024

Rolling back zod to 3.21.1 leads to my project not working any more. The reason is that this project uses uuid v7 and it seems that zod does not recognize uuid v7 as valid until later versions (3.22.4 works). For more info see electric-sql/electric#1153 (comment)

@canadaduane
Copy link

zod 3.23 has been released, and may include a fix for the XOR issue: colinhacks/zod#2184 (reference)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending Waiting on a response or on some dependency update
Projects
None yet
Development

No branches or pull requests

7 participants