question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature: Conditional Validation Similar to yup.when()

See original GitHub issue

Similar to this Yup issue: https://github.com/jquense/yup/issues/176 and creating a new issue out of #61.

Many users of zod would like to do conditional requirement or validation of fields based on either fields passed as context to zod, or based off of the value of another schema property. This is common to do in form validations.

The closed issue #61 addresses how to do conditional validation with superRefine. This works well enough in small cases, but many folks have large complex schemas and we would like to keep the existing validation on an object i.e. not have to make the entire object partial in order for conditional requirement to work.

This issue stems from the reaction to my comment https://github.com/colinhacks/zod/issues/61#issuecomment-1171958123

Pasting from the comment as my case is the same: I have large schema that needs to require one or another field. A nested partial Zod object with superRefine works for this.

What I want to be able to do however, is to do conditional requirement on 1 or 2 fields without making the entire object partial and while having access to all of the fields in the object.

Ex: I have a required enum that has two values: “ValueA” and “ValueB”

Upon “ValueA” then someOtherFieldA is required. Upon “ValueB” then someOtherFieldB is required.

There are also other required fields within the schema that should remain required without explicitly checking them in something like superRefine.

The reason I chose zod over yup was TypeScript support, but in yup’s beta versions TS support has improved a lot. Not having a functionality like this is a big blocker for me wanting to keep using zod. Thanks!

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:122
  • Comments:13 (2 by maintainers)

github_iconTop GitHub Comments

33reactions
snax4acommented, Sep 22, 2022

This is currently the only problem I have with zod - I have to do conditional field validation in superRefine which is not the problem but then if I want to use that schema in other places with extend() or merge() the problem starts.

I think that something like yup.when() is the only missing part in this schema validation library.

5reactions
colinhackscommented, Dec 12, 2022

Thanks for the response @deniskabana. The problem is that these refinements shouldn’t live inside the ZodDate instance. They should get attached to the ZodObject schema that contains startDate and endDate. Let me know if I’m still misunderstanding.

const schema = z
    .object({
      startDate: z.date().optional(),
      endDate: z.date().optional(),
      actualDate: z.date(),
    })
    .refine((val) => {
      if (!val.startDate && !val.endDate) return true;
      if (!val.startDate || !val.endDate) return false;
      return val.actualDate >= val.startDate && val.actualDate <= val.endDate;
    });

Note that you actually have typing on startDate and endDate because this approach doesn’t try to break locality, unlike the Yup example, in which Yup has no idea what the type should be on those values. Way less verbose and more typesafe. Use superRefine if you want to customize error codes or messages.

You can also define this refinement as a separate function and drop it into multiple schemas.

  const dateRangeValidator = (val: {
    startDate?: Date;
    endDate?: Date;
    actualDate: Date;
  }) => {
    if (!val.startDate && !val.endDate) return true;
    if (!val.startDate || !val.endDate) return false;
    return val.actualDate >= val.startDate && val.actualDate <= val.endDate;
  };
  
  const schema = z
    .object({
      startDate: z.date().optional(),
      endDate: z.date().optional(),
      actualDate: z.date(),
    })
    .refine(dateRangeValidator);
Read more comments on GitHub >

github_iconTop Results From Across the Web

Conditional Validation in Yup
when('preferredContact', { is: 'Phone', then: Yup.string() .required('Phone number is required.'), }), // This is another input field.
Read more >
Conditional validation of form fields using Yup
How to enable or disable validation on Formik form fields based on certain conditions in Yup.
Read more >
How To Do Conditional Validation With Formik and Yup
Formik and Yup provides a nice easy way to do conditional validation for your React projects. Using the when method you can conditionally...
Read more >
How to conditionally validate at least one of n values are set?
I have 5 form fields, at last one of which must be populated for validation to succeed. I attempted this, but soon ran...
Read more >
How to Create an Optional Dynamic Validation Schema based ...
In this lesson we'll show how to setup a nested validation structure using the `yup` library. We'll then use the `yup.lazy` method to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found