zod-prisma icon indicating copy to clipboard operation
zod-prisma copied to clipboard

Relation model definitions throw TypeScript errors

Open franky47 opened this issue 3 years ago • 11 comments

Generated Zod schemas for complete records (with relations) report errors, see test/functional/recursive/expected/comment.ts:

Type 'ZodLazy<ZodObject<extendShape<{ id: ZodString; author: ZodString; contents: ZodString; parentId: ZodString; }, { parent: ZodType<CompleteComment, ZodTypeDef, CompleteComment>; children: ZodArray<...>; }>, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'ZodType<CompleteComment, ZodTypeDef, CompleteComment>'.
  Types of property '_type' are incompatible.
    Type '{ id?: string; contents?: string; author?: string; parentId?: string; parent?: CompleteComment; children?: CompleteComment[]; }' is not assignable to type 'CompleteComment'.
      Property 'parent' is optional in type '{ id?: string; contents?: string; author?: string; parentId?: string; parent?: CompleteComment; children?: CompleteComment[]; }' but required in type 'CompleteComment'.ts(2322)

I'll have a closer look and open a PR if I find a fix.

franky47 avatar Dec 14 '21 20:12 franky47

I'll take a look at this and your other PRs tomorrow. Thank you for all your contribution! <3

CarterGrimmeisen avatar Dec 14 '21 23:12 CarterGrimmeisen

Fixed with release 0.3.1

CarterGrimmeisen avatar Dec 15 '21 23:12 CarterGrimmeisen

Hey @CarterGrimmeisen! I'm still seeing this issue, with the TS errors in version ^0.3.2

siddharthsharma94 avatar Dec 22 '21 07:12 siddharthsharma94

@siddharthsharma94 can you paste your Prisma schema for the relevant parts where you see this error?

0.3.1 fixed the issue for me, though I still have errors described in #52 due to JSON fields.

franky47 avatar Dec 22 '21 07:12 franky47

@CarterGrimmeisen @franky47

I encountered same error. I think we can reproduce that using test code. https://github.com/CarterGrimmeisen/zod-prisma/issues/61

camelmasa avatar Dec 30 '21 03:12 camelmasa

I will reopen this issue to document some continued problems users are seeing but I won't be totally sure they exist until we can see a prisma schema that replicates the issue.

CarterGrimmeisen avatar Dec 30 '21 04:12 CarterGrimmeisen

I think I hit this bug too.

this is the schema:

model user {
    id        Int      @id @default(autoincrement())
    email     String   @unique
    password  String
    name      String
    enabled   Boolean @default(true)

    group_id  Int
    group     group @relation(fields: [group_id], references: [id])
}

model group {
    id        Int      @id @default(autoincrement())
    
    child_groups    group[] @relation("parent_child_group")

    parent_id       Int?
    parent          group? @relation("parent_child_group", fields: [parent_id], references: [id])

    users           user[]
    name            String

    locations locationmap[]
}

and this is the error I get

TS2322: Type 'ZodLazy<ZodObject<extendShape<{ id: ZodNumber; email: ZodString; password: ZodString; name: ZodString; enabled: ZodBoolean; group_id: ZodNumber; }, { ...; }>, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'ZodType<Completeuser, ZodTypeDef, Completeuser>'.
  Types of property '_type' are incompatible.
    Type '{ id?: number; group?: Completegroup; name?: string; email?: string; password?: string; enabled?: boolean; group_id?: number; }' is not assignable to type 'Completeuser'.
      Property 'group' is optional in type '{ id?: number; group?: Completegroup; name?: string; email?: string; password?: string; enabled?: boolean; group_id?: number; }' but required in type 'Completeuser'.

this is generated in user.ts

export const userModel = z.object({
  id: z.number().int(),
  email: z.string(),
  password: z.string(),
  name: z.string(),
  enabled: z.boolean(),
  group_id: z.number().int(),
})

export interface Completeuser extends z.infer<typeof userModel> {
  group: Completegroup
}

/**
 * RelateduserModel contains all relations on your model in addition to the scalars
 *
 * NOTE: Lazy required in case of potential circular dependencies within schema
 */
export const RelateduserModel: z.ZodSchema<Completeuser> = z.lazy(() => userModel.extend({
  group: RelatedgroupModel,
})) 

and this is generated in group.ts

export const groupModel = z.object({
  id: z.number().int(),
  parent_id: z.number().int().nullish(),
  name: z.string(),
})

export interface Completegroup extends z.infer<typeof groupModel> {
  child_groups: Completegroup[]
  parent?: Completegroup | null
  users: Completeuser[]
  locations: Completelocationmap[]
}

/**
 * RelatedgroupModel contains all relations on your model in addition to the scalars
 *
 * NOTE: Lazy required in case of potential circular dependencies within schema
 */
export const RelatedgroupModel: z.ZodSchema<Completegroup> = z.lazy(() => groupModel.extend({
  child_groups: RelatedgroupModel.array(),
  parent: RelatedgroupModel.nullish(),
  users: RelateduserModel.array(),
  locations: RelatedlocationmapModel.array(),
}))

markoheric avatar Feb 18 '22 17:02 markoheric

Hey @markoheric! Do you have typescript's strict mode enabled? Both zod and this package require it and the issue your describing looks suspiciously like strict mode being disabled. If not, let me know and we can look at it more closely!

CarterGrimmeisen avatar Feb 18 '22 17:02 CarterGrimmeisen

Hi @CarterGrimmeisen, I'm experiencing the same thing and I have strict mode true in my tsconfig compiler options.

schema.prisma file:

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

generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native", "rhel-openssl-1.0.x"]
}

generator zod {
  provider                 = "zod-prisma"
  output                   = "../schema"
  relationModel            = true
  modelCase                = "PascalCase"
  modelSuffix              = "Model"
  useDecimalJs             = true
  prismaJsonNullability    = true
}

model Basket {
  id Int @id @default(autoincrement())
  basketToken String @unique
  createdOn DateTime @default(now())
  lastUpdated DateTime?
  validBasket Boolean @default(false)
  totalCost Float
  originalCost Float

  coupon String?
  creditUsed Float?
  couponDiscount Float?

  orders Order[]
  catalogueId String
}

model Order {
  id Int @id @default(autoincrement())
  orderToken String @unique

  basket Basket @relation(fields: [basketId], references: [id])
  basketId Int 

  items BasketItem[]

  expiryDate DateTime?
  date DateTime?
  address Json?
}

model BasketItem {
  id Int @id @default(autoincrement())
  title String
  description String?

  order Order @relation(fields: [orderId], references: [id])
  orderId Int

  lineCost Float
  sku String
  qty Int
  price Float?
}

dependencies:

{
  "devDependencies": {
    "@prisma/client": "^3.10.0",
    "@types/jest": "^26.0.4",
    "@types/node": "^14.0.14",
    "prisma": "^3.10.0",
    "zod-prisma": "^0.5.4",
    "js-yaml": "^4.1.0",
    "dotenv": "^8.2.0",
    "fs-extra": "^9.0.1",
    "jest": "^26.1.0",
    "nanoid": "^3.1.22",
    "nodemon": "^2.0.3",
    "reflect-metadata": "^0.1.13",
    "ts-jest": "^26.1.1",
    "ts-loader": "^7.0.5",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12",
    "typescript": "^4.6.2"
  },
  "dependencies": {
    "node-ts": "^5.0.6",
    "zod": "^3.13.4"
  }
}

jamespb97 avatar Mar 15 '22 16:03 jamespb97

Fixed it, make sure your generated zod folder is in your includes in tsconfig! https://github.com/colinhacks/zod/issues/533

By default this generator puts zod in prisma folder which wasn't included in my tsconfig. Either move the zod folder to be somewhere else or include in tsconfig like so:

{
  "includes": ["prisma/zod"]
}

jamespb97 avatar Mar 16 '22 10:03 jamespb97

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true, // <- changed
    "strictNullChecks": true, // <- added just in case
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

Just change ts.config

Azoom-Le-Van-Thuong avatar Sep 23 '23 07:09 Azoom-Le-Van-Thuong