Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple validations on React PropTypes

Is there a way to have multiple validations on a single prop using React.PropTypes. specifically want to blend a custom validation and a stock validation.

I have two props, an object options, and a string value. i want to check that props.value is a string but also a key on the object. using coffeescript this looks like:

propTypes:
  options: React.PropTypes.Object.isRequired
  value: (props, propName, componentName) ->
    unless props[propName] of props.options
      new Error('my custom message')

this works great, but i also want to ensure that my value is a string type. I'm sure i can manually stick in that validation in the custom function no problem, but ideally, i'd just like to use React.PropTypes.string.isRequired. ive tried just putting it in the custom function and executing it but that did not work. the following didn't work either:

  value: React.PropTypes.string.isRequired && (props, propName, componentName) ->
    unless props[propName] of props.options
      new Error('my custom message')

is there a way to get this working using reacts built in validator, or is rewriting it in my function the only option?

like image 272
PhilVarg Avatar asked Jul 01 '15 16:07

PhilVarg


1 Answers

From the Reusable Components page in the docs:

You can also specify a custom validator. It should return an Error
// object if the validation fails. Don't `console.warn` or throw, as this
// won't work inside `oneOfType`.
customProp: function(props, propName, componentName) {
  if (!/matchme/.test(props[propName])) {
    return new Error('Validation failed!');
  }
}

So a propType returns nothing or an error object. We can write a 'all' function which takes two propTypes and merges the result.

const allPropTypes = (...types) => (...args) => {
  const errors = types.map((type) => type(...args)).filter(Boolean);

  // no errors? cool!
  if (errors.length === 0) return;

  // collect the messages and join them together
  const message = errors.map((e) => e.message).join('\n');
  return new Error(message);
};

Then you can use this to assert against multiple propTypes.

propTypes = {
  foo: allPropTypes(
    PropTypes.string.isRequired,
    (props, propName, componentName) => props.options && props.options[props[propName]] 
      ? undefined
      : new Error(
          `${componentName}: expected prop ${propName}="${prop[propName]}"` 
          + `to be a key of prop "options" `
          + `(one of ${Object.keys(props.options).join(', ')})`
        )
  )
}

Note: none of this is tested, but no syntax errors! You can compile it to es3 with babel, or convert it to CS by hand.

like image 181
Brigand Avatar answered Oct 19 '22 17:10

Brigand