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

[BUG] TypeError: keyValidator._parse is not a function #12

Open
iamyuu opened this issue Nov 4, 2022 · 14 comments
Open

[BUG] TypeError: keyValidator._parse is not a function #12

iamyuu opened this issue Nov 4, 2022 · 14 comments

Comments

@iamyuu
Copy link

iamyuu commented Nov 4, 2022

using separate zod schema doen't work

🚀 ~ action ~ error TypeError: keyValidator._parse is not a function
    at ZodObject._parse (types.js:1188:37)
    at ZodObject._parseSync (types.js:109:29)
    at ZodObject.safeParse (types.js:139:29)
    at ZodObject.parse (types.js:120:29)
    at Object.parseForm (index.js:50:22)
    at async action (main.tsx:25:20)
    at async callLoaderOrAction (router.ts:2530:14)
    at async handleAction (router.ts:981:16)
    at async startNavigation (router.ts:904:26)
    at async Object.navigate (router.ts:784:12)

here the repo for reproduce: zodix-rr-reproduce

@rileytomasek
Copy link
Owner

rileytomasek commented Nov 5, 2022

Thanks for the bug report and clean reproduction. I stepped through the code and this line is causing the problem:

const finalSchema = schema instanceof ZodType ? schema : z.object(schema);

The instanceof check is returning false so it's wrapping the schema in z.object() and causing the issue. There is already a test for this so I think the issue is caused by Vite.

@colinhacks is there a way to check if the schema is a ZodRawShape vs a ZodObject that is more resilient?

@iamyuu
Copy link
Author

iamyuu commented Nov 6, 2022

I think the actually issues is missing something on the zodix package, but I'm not sure what it's missing, because if I'm copy the whole package to my source file it's works

@rileytomasek
Copy link
Owner

That makes sense because the dependency resolution would be less error prone that way.

Regardless, I just tested your repro with the v0.3.0 release and it's working now.

@iamyuu
Copy link
Author

iamyuu commented Nov 9, 2022

hey @rileytomasek, when using parseForm it works, but I need the error validation and I don't wanna throw when parsing fails, I saw on the docs we can use parseFormSafe, but when using that function the error is still there

@ZeevG
Copy link

ZeevG commented Dec 5, 2022

I'm running into this issue in my project. Removing the following check seems to fix it

const finalSchema = schema instanceof ZodType ? schema : z.object(schema);

We're using esbuild so it could be because of that. I haven't dug in too deep but without esbuild it seems to work. It would be good to have a fix.

Edit: A suitable workaround (or maybe actually the intended way to use this library) is to pass a zod schema instead of a zod object.

eg from the docs

zx.parseParams(params, { id: z.string() })

instead of

zx.parseParams(params, z.object({ id: z.string() }))

@toddheslin
Copy link

This is still a problem for me when testing my remix action using vitest. Using latest 0.4.0.

@ZeevG's solution works fine but doesn't work if you need to infer from the schema to pass around.

I previously have defined:

export type SnipFormInput = z.infer<typeof snipFormInput>
export const snipFormInput = z.object({
  // ...
})

But because I kept getting this error when running tests, I needed to create an intermediate object.

export type SnipFormInput = z.infer<typeof snipFormInput>
export const snipFormInputObject = {
  // ...
}
export const snipFormInput = z.object({ ...snipFormInputObject })

It's a bit hacky, but it lets me run my tests. It's likely a vite issue but if we find a workaround, we should document it so others don't need spend too much time on it.

@tatemz
Copy link

tatemz commented Jan 30, 2023

I also get this error when passing in a z.union() schema

After looking into this a bit deeper, this likely is an issue with instanceof when using various build mechanisms. When a class is defined and bundled into a package (e.g. using esbuild) then zodix and your application could be using TWO different bundled copies of the ZodType class.

In other words - instanceof is strict, so your schema is created using ZodTypeA and then is checked within zodix for instanceof ZodTypeB, which would always return false

@rileytomasek
Copy link
Owner

@tatemz I was able to reproduce the duplicate instanceof issue when debugging this initially. Interestingly, this seems only to happen for Vite and not esbuild or others.

I'm open to PRs if someone finds a way to do that check without using instanceof.

@tatemz
Copy link

tatemz commented Jan 31, 2023

if someone finds a way to do that

If only there was a library that could help us check if an object matched a certain schema structure 🤔 😆

Joking aside, from the looks of it, the only thing that part of the code cares about is that the object has a .parse() method on it that can receive data to parse.

Maybe a typeguard could help?

const isZodType = (input: ZodRawShape | ZodTypeAny): input is ZodType => typeof raw.parse === "function"

@ghost
Copy link

ghost commented Feb 20, 2023

Could we please re-open this issue? Like @toddheslin, I am also using Vitest and the workaround at the moment seems to be storing the schema shape in a separate variable.

export type Schema = z.infer<typeof schema>
export const schemaInput = {
  // ...
}
export const schema = z.object({ ...schemaInput })

@toddheslin
Copy link

I agree, this needs to be reopened. Whilst my little trick worked for simple input objects, similar to @tatemz it breaks down when I have a union (or in my case a discriminated union) type:

export const formSubmissionInput = z
  .discriminatedUnion('snipMedium', [
    // refactored out into plain objects, hoping it would help
    z.object({ ...formSubmissionInputObjectEmail }),
    z.object({ ...formSubmissionInputObjectSms }),
  ])
  .refine(
    (val) => {
      if (val.snipMedium === 'sms') {
        return validatePhoneNumber({
          country: val.phoneCountry,
          number: val.phoneNumber,
        })
      }
      return true
    },
    () => ({ message: 'Phone number is invalid', path: ['phoneNumber'] })
  )

@rileytomasek can we reopen this so it's clear a PR is needed?

@rileytomasek
Copy link
Owner

I'm reopening this in case one of you want to take a shot at a PR. Given that it's actually a Vite issue, I won't be able to prioritize fixing it any time soon.

@ghost
Copy link

ghost commented Mar 5, 2023

PR created here based on @tatemz comments #32

@colemars
Copy link

colemars commented Apr 5, 2024

Seeing this with RSBuild/RSPack, not using Vite at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants