Yup: Empty string inconsistency

Created on 20 Feb 2020  路  4Comments  路  Source: jquense/yup

Hi.

I wonder why, empty strings, are considered valid as for email and url methods, but invalid for the rest of the methods?

I've read this issue https://github.com/jquense/yup/issues/667 and I think the user who posted it has a point.

yup.object().shape({
    email: yup.string().email(),
    name: yup.string().min(3).max(100),
    taxId: yup.string().uppercase().length(9).matches(/^[0-9]{8}[A-Z]$/),
}).validateSync({
    email: '',
    name: '',
    taxId: ''
});

IMHO the above code should return that the object is valid, cause none of the properties are reqquired.
But it doesn't. Both name and taxId are invalid.

Maybe create another method like empty or notEmpty for strings? (like required/notRequired or nullable)

yup.object().shape({
    email: yup.string().empty().email(),
    name: yup.string().empty().min(3).max(100),
    taxId: yup.string().empty().uppercase().length(9).matches(/^[0-9]{8}[A-Z]$/),
}).validateSync({
    email: '',
    name: '',
    taxId: ''
});
enhancement question

Most helpful comment

For any wanderer in the future; If you want to have .min(n) for strings that will check for min length _but_ will also allow you a 0 length string (because it's not a required field) you can emulate this behavior with:

string().test(
      'min8',
      'This must be at least 8 characters long',
      value => (value.trim().length > 0 ? value.length >= 8 : true)
    )

Changing 8 with your number of choice.

All 4 comments

We ran to this issue also. There is code written for url and email validations to behave like this https://github.com/jquense/yup/blob/master/src/string.js#L100 and https://github.com/jquense/yup/blob/master/src/string.js#L108

removing excludeEmptyString from url and email would make more sense in my mind. For example const contactDetails = yup.object({ name: yup.string().required(), email: yup .string() .email() .notRequired(), }) would behave as Joi validation. Email is optional but if it's defined then it must be a email. Empty string is still a definition.

Don't know if there are other implications though. url, and email validations seem the only ones using this behaviour as defaults. It could also be that signature would be changed to same as with string.matches https://github.com/jquense/yup#stringmatchesregex-regex-options--message-string-excludeemptystring-bool--schema and default to false

@hixus removing excludeEmptyString would make those strings always required, since the empty string will fail the regex. The reason empty strings are excluded is precisely to allow you to use required here. It also means you can provide clearer errors, instead of "Invalid email address" for an empty input

I removed the excludeEmptyString and tried yup.string().email().validateSync(undefined). It accepted undefined so the change didn't make it always required.

As the issue keeps coming up what would be the preferred solution for rule "valid email or undefined"? I could add it to the readme. For orm, it's easy to strip away undefined values but with empty strings it does not know if the empty string is actually wanted.

For any wanderer in the future; If you want to have .min(n) for strings that will check for min length _but_ will also allow you a 0 length string (because it's not a required field) you can emulate this behavior with:

string().test(
      'min8',
      'This must be at least 8 characters long',
      value => (value.trim().length > 0 ? value.length >= 8 : true)
    )

Changing 8 with your number of choice.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ScreamZ picture ScreamZ  路  4Comments

jakke-korpelainen picture jakke-korpelainen  路  4Comments

haddyo picture haddyo  路  3Comments

rigids picture rigids  路  3Comments

laurazenc picture laurazenc  路  3Comments