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?
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.