How to condense Yup "when" validations

Snekse picture Snekse · Nov 20, 2018 · Viewed 12.3k times · Source

I have several fields that are required if a single condition is true. Is there a better way to condense this code to avoid repeating the when for all of these fields?

const requiredForDiffAddress = {
    is: false,
    then: Yup.string().required()
};

export const BillingAddressYupValidationSchemaShape = {
  useShippingAddress: Yup.boolean().default(true).required(),
  street: Yup.string()
      .when('useShippingAddress', requiredForDiffAddress),
  city: Yup.string()
      .when('useShippingAddress', requiredForDiffAddress),
  state: Yup.string()
      .when('useShippingAddress', requiredForDiffAddress),
  zipCode: Yup.string()
      .when('useShippingAddress', requiredForDiffAddress),
};

Or for a more realistic and involved sample

const buildRequiredForDiffAddress = requiredText => ({
    is: false,
    then: Yup.string().required(requiredText)
});

export const BillingAddressYupValidationSchemaShape = {
  useShippingAddress: Yup.boolean().default(true).required(),
  street1: Yup.string().when('useShippingAddress', 
      buildRequiredForDiffAddress("How will we know where to send your order?")),
  city: Yup.string().when('useShippingAddress', 
    buildRequiredForDiffAddress("What city do you live in?")),
  state: Yup.string().when('useShippingAddress',
    buildRequiredForDiffAddress("State please!")),
  zipCode: Yup.string().when('useShippingAddress', 
      buildRequiredForDiffAddress("Zip Code please!")),
};

Answer

Snekse picture Snekse · Nov 20, 2018

TL;DR: The solution posted in the question is probably the best way to handle fields that are required only when a condition is met based off the value of some other field*

Extended Answer

I've looked at this quite a bit after messaging the creator of Yup.

He suggested

extend mixed with a requiredIf method to encapsulate this sort of thing

I looked into what would be involved with that along with using some form of lazy. The extension route seemed to be better than the lazy route, but in the end, I feel like what I have is probably the best solution.

I created this fairly detailed CodeSandbox is someone wants to take a stab and find a better solution. I'll gladly change the accepted answer for this.

https://codesandbox.io/s/xk4r7nq9z

* ...and you want custom error messaging per field. It seems as if you are okay w/ the default messaging, then the example posted may not be the simplest solution.