React.PropTypes array with specific length

Solution 1:

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.

Solution 2:

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.`
      )
    }
  }

Solution 3:

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`);
}