chrishoermann / zod-prisma-types

Generator creates zod types for your prisma models with advanced validation
Other
579 stars 43 forks source link

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

Open atanaskanchev opened 1 year ago

atanaskanchev commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

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

chrishoermann commented 1 year ago

Opened an issue in the zod repo: https://github.com/colinhacks/zod/issues/2184

ianhernandez commented 1 year ago

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 commented 1 year ago

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 commented 8 months ago

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 = 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;

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.

barbalex commented 3 months ago

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 https://github.com/electric-sql/electric/issues/1153#issuecomment-2055583872

canadaduane commented 2 months ago

zod 3.23 has been released, and may include a fix for the XOR issue: https://github.com/colinhacks/zod/issues/2184#ref-pullrequest-2254755159