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

Custom validations not running if default types fail. #259

Closed
turbochef opened this issue Dec 8, 2020 · 7 comments
Closed

Custom validations not running if default types fail. #259

turbochef opened this issue Dec 8, 2020 · 7 comments
Labels
wontfix This will not be worked on

Comments

@turbochef
Copy link

turbochef commented Dec 8, 2020

May be a copy of #68 but I'm still seeing this issue. Using version: 2.0.0-beta.26

const someSchema = z
  .object({
    name: z.string().nonempty("name required."),
    lower_bound: z.number(),
    upper_bound: z.number(),
  })
  .refine((val) => val.lower_bound < val.upper_bound, {
    message: "Upper bound must be greater than lower bound.",
    path: ["lower_bound", "upper_bound"],
  });

  console.log(
    someSchema
    .safeParse({name: "", lower_bound: 100, upper_bound: 0})
    .error
    .issues
  );

  // OUTPUT:
  // [
  //   {
  //     "code": "too_small",
  //     "minimum": 1,
  //     "type": "string",
  //     "inclusive": true,
  //     "message": "name required.",
  //     "path": [
  //       "name"
  //     ]
  //   }
  // ]
@pfcodes
Copy link

pfcodes commented Dec 31, 2020

Having the same issue using 2.0.0-beta.29. The desired result is to have all errors output at the same time.

@colinhacks
Copy link
Owner

colinhacks commented Jan 3, 2021

This is a hard issue to solve. Refinements assume that the input has already been validated properly. It's why Zod is able to strongly type val. If a type error has already occurred during type checking, Zod can't guarantee that val is of type { name: string, lower_bound: number, upper_bound: number }. Which means the refinement will possibly throw.

I could just run all refinements, even if type errors are already detected. Currently Zod doesn't catch errors thrown in refinements but it could. This way I could "safely" run all refinements. But you don't want all the refinement errors to appear if a completely incorrect value is passed into schema. For instance, it would be odd if you received a "Upper bound must be greater than lower bound" error if you tried someSchema.parse('not an object'). It's tricky.

@pfcodes
Copy link

pfcodes commented Jan 3, 2021

@colinhacks

But you don't want all the refinement errors to appear if a completely incorrect value is passed into schema.

Could refinements catch all errors except for that single case?

@colinhacks
Copy link
Owner

Possibly. I could consider certain issues "fatal" and others non-fatal. For instance, the issue thrown by z.string().nonempty("name required.") is a ZodTooSmallIssue which is usually non-fatal. It's not a very elegant solution though.

@andreyfel
Copy link

I've also faced this issue. A workaround which I found was to split the original schema into 2 and intersect them:

const schema1 = z.object({
  name: z.string().nonempty("name required."),
})

const schema2 = z
  .object({
    lower_bound: z.number(),
    upper_bound: z.number(),
  })
  .refine((val) => val.lower_bound < val.upper_bound, {
    message: "Upper bound must be greater than lower bound.",
    path: ["lower_bound", "upper_bound"],
  });

const someSchema = z.intersect(schema1, schema2);

The main issue with this approach is that intersect accepts only 2 arguments and sometimes I need to intersect more than 2 objects. union accepts an array and I would expect intersect and union to have the same API. @colinhacks is there a limitation that doesn't allow intersect to accept an array?

Also, I was wondering if I could use merge or extend the objects but the final object acts as in the original example. refine is invoked only when the whole object is valid, not the sub-object.

@bgoscinski
Copy link

bgoscinski commented Dec 2, 2021

I also just run into this problem :(

This is a hard issue to solve. Refinements assume that the input has already been validated properly.

Another idea that comes to my mind is to add a new method that would be like .superRefine except it wouldn't guarantee that the input will have correct type/shape (the callback could even accept unknown as input value). Since it would be a new method it would not cause a breaking change. WDYT @colinhacks?

@stale
Copy link

stale bot commented Mar 2, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix This will not be worked on label Mar 2, 2022
@stale stale bot closed this as completed Mar 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

5 participants