DEV Community

Omar Dulaimi
Omar Dulaimi

Posted on

How to validate multiple schemas for the same field with Yup?

For someone used to working with Joi, this syntax is something I'm very familiar with:

  title: Joi.alternatives().try(
    Joi.string(),
    Joi.object(SchemaObject)
  )
Enter fullscreen mode Exit fullscreen mode

But unfortunately it is not supported in Yup out of the box.
So, I figured out a way to make this work.

First, we need to add a new method to Yup:

yup.addMethod(yup.MixedSchema, "oneOfSchemas", function (schemas: Yup.AnySchema[]) {
  return this.test(
    "one-of-schemas",
    "Not all items in ${path} match one of the allowed schemas",
    (item) =>
      schemas.some((schema) => schema.isValidSync(item, { strict: true }))
  );
});
Enter fullscreen mode Exit fullscreen mode

Then, we can use it as follows:

title: yup
  .mixed()
  .oneOfSchemas([
    yup.string(),
    yup.object().noUnknown().shape(SchemaObject2),
  ]);
Enter fullscreen mode Exit fullscreen mode

That's all!

Top comments (1)

Collapse
 
sergsar profile image
sergsar

Thank you, that helped me. However, since this approach doesn’t cast the value, I’d suggest using the following code instead.:

export const oneOfSchemas: Parameters<typeof yup.addMethod> = [
  yup.MixedSchema,
  'oneOfSchemas',
  function (schemas: yup.AnySchema[]) {
    return (this as yup.AnySchema).when(
      (values, schema, options) => schemas.find(one => one.isValidSync(options.value)) || schemas[0]
    )
  }
]
Enter fullscreen mode Exit fullscreen mode

Also for Typescript need to register the function:

import { AnySchema } from 'yup'

declare module 'yup' {
  interface MixedSchema {
    oneOfSchemas<T>(schemas: AnySchema[]): MixedSchema<T>
  }
}
Enter fullscreen mode Exit fullscreen mode