Reputation: 37238
Is it possible to use React.PropTypes
to enforce length's on an array?
Here is a very simple case:
const TWO_NUMBERS = PropTypes.array; // i need this to be an array of two numbers
I know in javascript arrays are just objects so I tried this:
const TWO_NUMBERS = PropTypes.shape({
0: PropTypes.number.isRequired,
1: PropTypes.number.isRequired,
});
However this keeps telling warning me expected an object but got an array
.
Upvotes: 16
Views: 16432
Reputation: 6980
In this case you would need to write your own special PropTypes function which react provides you to do.
const TWO_NUMBERS = function(props, propName, componentName) {
if (!Array.isArray(props.TWO_NUMBERS) || props.TWO_NUMBERS.length != 2 || !props.TWO_NUMBERS.every(Number.isInteger)) {
return new Error(`${propName} needs to be an array of two numbers`);
}
return null
}
This would throw an error if TWO_NUMBERS
isn't an array, isn't an array of two, and isn't an array of only integers.
You can get information about proptype functions here:
https://facebook.github.io/react/docs/typechecking-with-proptypes.html#react.proptypes
Its at the bottom of that example block.
Upvotes: 14
Reputation: 9319
A custom function would be the correct approach here.
const propTypes = {
TWO_NUMBERS: arrayOfLength.bind(null, 2)
}
const arrayOfLength = (expectedLength, props, propName, componentName) => {
const arrayPropLength = props[propName].length
if (arrayPropLength !== expectedLength) {
return new Error(
`Invalid array length ${arrayPropLength} (expected ${expectedLength}) for prop ${propName} supplied to ${componentName}. Validation failed.`
)
}
}
Upvotes: 9
Reputation: 23280
Inspired by the answer of @finalfreq, I came up with this. It handles two numbers (floats in this case) and can also be used as arrayOf(twoNumbers)
. Not sure how to make it work like twoNumbers.isRequired
yet...
Also I think the code is cleaner and easier to follow if you don't use the negation in the validation comparison.
import invariant from 'invariant';
function isValid(value) {
return Array.isArray(value) && value.length === 2 && value.every(Number.isFinite);
}
export default function twoNumbers(props, propName, componentName) {
if (Array.isArray(props)) {
props.forEach((item, index) => {
invariant(
isValid(item),
`Array item index ${index} is ${item}, but needs to be an array of two numbers`
);
});
}
const value = props[propName];
if (!value) return; // not required so could be null
invariant(isValid(value), `${componentName} ${propName} needs to be an array of two numbers`);
}
Upvotes: 1
Reputation: 40448
PropTypes
checks for types not for attributes. Also, checking for PropTypes
is disabled in production mode. That makes it impossible for PropTypes
to check for ever changing array lengths during run-time.
Upvotes: -5