Yup: .required on array is requiring minimum of 1

Created on 14 Aug 2019  Â·  17Comments  Â·  Source: jquense/yup

I want my schema to require that the field "ads" is an array. It can be empty. I created this schema:

const YUP_SCHEMA = yup.object({
    ads: yup.array().of(......).required()
});

However this is requiring that ads be an array with at least one element. I also tried to add .required().min(0) but it is still not allowing it. The only way I got it to work was by removing .required() but now I don't see the error when ads is undefined/null.

Most helpful comment

hello, as promised:

function arrayRequiredAllowEmpty<T>(this: yup.ArraySchema<T>, message?: string) {
  return this
    .test('field is required', message || '', (value) =>
      _.isArray(value)
    )
}
// https://github.com/jquense/yup/issues/312#issuecomment-442854307
yup.addMethod(yup.array, 'requiredAllowEmpty', arrayRequiredAllowEmpty);
declare module 'yup' {
  interface ArraySchema<T> {
    requiredAllowEmpty<T>(message?: string): ArraySchema<T>
  }
}

let schema = yup.array().requiredAllowEmpty();

console.log(schema.cast([1]));
console.log(schema.cast([]));
console.log(schema.isValidSync(null));
console.log(schema.isValidSync(undefined));

I used .isValidSync to avoid exceptions in the last two cases.
I'd be very happy to explain any details.

All 17 comments

hello, /README.md#arrayrequiredmessage-string--function-schema says:

empty arrays are also considered 'missing' values

Thanks @RichardYan314 is there anyway to require an array with length of 0 or more?

I guess you need to write your own function and use it in .test().

alternatively you could extend Yup, see README.md under heading "Adjust core Types" (sorry there is no anchor).

I will try to implement this during the weekend.

Thank you @RichardYan314! From seeing your example for my use case it will help me understand it the best, and I will be able to provide more extensions! Very nice of you! Thank you!

hello, as promised:

function arrayRequiredAllowEmpty<T>(this: yup.ArraySchema<T>, message?: string) {
  return this
    .test('field is required', message || '', (value) =>
      _.isArray(value)
    )
}
// https://github.com/jquense/yup/issues/312#issuecomment-442854307
yup.addMethod(yup.array, 'requiredAllowEmpty', arrayRequiredAllowEmpty);
declare module 'yup' {
  interface ArraySchema<T> {
    requiredAllowEmpty<T>(message?: string): ArraySchema<T>
  }
}

let schema = yup.array().requiredAllowEmpty();

console.log(schema.cast([1]));
console.log(schema.cast([]));
console.log(schema.isValidSync(null));
console.log(schema.isValidSync(undefined));

I used .isValidSync to avoid exceptions in the last two cases.
I'd be very happy to explain any details.

Just seeing this, excuse my delay. This is super super cool! I will break it down when I use it in my project and learn from it. Thanks for offering for Q&A I will definitely ask when it comes up. I will get to applying this on the upcoming weekend, and will let you know how things go! Thank you!!

Should we close this issue? Maybe I can add this snippet into the readme for examples of writing custom one.

you can close this issue as soon as you can confirm my solution works. I cannot close issues here because I am just a passer-by and not related to this project. But I'd be happy to help.

---Original---
From: "YasirZillow"notifications@github.com
Date: Tue, Aug 20, 2019 05:31 AM
To: "jquense/yup"yup@noreply.github.com;
Cc: "Mention"mention@noreply.github.com;"Ritsuka"richardyan314@foxmail.com;
Subject: Re: [jquense/yup] .required on array is requiring minimum of 1 (#600)

Just seeing this, excuse my delay. This is super super cool! I will break it down when I use it in my project and learn from it. Thanks for offering for Q&A I will definitely ask when it comes up. I will get to applying this on the upcoming weekend, and will let you know how things go! Thank you!!

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

Thanks Richard I will for sure verify and close then. Thanks!

In case somebody tried to implement @RichardYan314 's solution in a Typescript project and came across a parsing error between ArraySchema and Schema, here's an abstraction I came up with to make it work with TS:

addMethod(array, 'requiredAllowEmpty', function <T>(
    this: Schema<T>,
    message?: string,
) {
    return this.test('field is required', message || '', (value: any) =>
        _.isArray(value),
    );
});
declare module 'yup' {
    interface ArraySchema<T> {
        requiredAllowEmpty<T>(message?: string): ArraySchema<T>;
    }
}

Thanks a lot for the solution, @RichardYan314 ! Saved me many repeated test()s around my project!

you can also use array().defined()

@jquense That solution doesn't work out for my purposes, for the field could be undefined, just couldn't be any type other than an array of numbers including an empty array.
But should work out for more use cases than mine alone!

@jquense using that allows for the value to be null - which is not an empty array.

It would really be great if we could easily define this for validation - passing empty arrays as arguments is a very common use case, as we can use them by default with .map and other array operations even when empty.

The current default is fine, because you want to cover potential mistakes of people sending empty arrays. But there needs to be a way to also tell Yup that we are cool with an empty array too.

Something like this should work:

array().min(0).required();

If we are explicit with .min(0) I would hope Yup would be smart enough to accept an empty array.

You can use .defined()

You can use .defined()

As I mentioned in the first line of my post- all that does is not allow undefined values - it does not guarantee that what is there is an empty array.

To quote the docs:

Mark the schema as required but nullable. All field values apart from undefined meet this requirement.

Hence null is acceptable too.

I've tried to make it work with .defined() and I just can't:

const schema = yup.array().defined();

const emptyArray = [];
const notArray = null;
const notArrayTwo = "what";

// run schema validation on all of them one by one

Those all pass.

const schema = yup.array().required().defined();

const emptyArray = [];
const notArray = null;
const notArrayTwo = "what";

// run schema validation on all of them one by one

Those all fail.

Am I doing something wrong?

Hmm sounds like a bug with defined, it should not allow null. You can also try putting the min(0) after the required, since order matters and required also sets min()

Unfortunately that doesn't work either:

const schema = yup.array().required().min(0);

const emptyArray = [];

await schema.validate(emptyArray);

It might be worth considering adding an additional flag for strings and arrays, such as allowEmpty. Would be quite readable and concise:

const schema = yup.array().allowEmpty().required();

But making min(0) work out as expected is also cool and deliberate.

Was this page helpful?
0 / 5 - 0 ratings