The right React Component PropTypes for es6 (Weak) Maps, Sets

11,709

Solution 1

elementsMap: p.instanceOf(Map).isRequired

Solution 2

It's not convenient, but it's possible to write your own PropType.

From React's source (which it unfortunately does not expose at this point):

function createChainableTypeChecker(validate) {
  function checkType(isRequired, props, propName, componentName, location, propFullName) {
    componentName = componentName || ANONYMOUS;
    propFullName = propFullName || propName;
    if (props[propName] == null) {
      var locationName = ReactPropTypeLocationNames[location];
      if (isRequired) {
        return new Error('Required ' + locationName + ' `' + propFullName + '` was not specified in ' + ('`' + componentName + '`.'));
      }
      return null;
    } else {
      return validate(props, propName, componentName, location, propFullName);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

Which you can use like so:

const map = createChainableTypeChecker(function(props, propName, componentName, location, propFullName) {
    if (...) {
        return null; // pass the check
    }
    return new Error('Error message'); // fail the check
});

Solution 3

Try using a custom property validator function (from the documentation):

// 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 that might look something like:

static propTypes = {
    elementMap: (props, propName) => {
        const m = props[propName];
        if (!m) { return new Error(`Required property ${propName} not supplied`); }
        if (!(m instanceof Map)) { return new Error("must be a Map"); }
        // check contents of map if you want...
    },
};
Share:
11,709

Related videos on Youtube

Vitali Zaidman
Author by

Vitali Zaidman

Updated on September 15, 2022

Comments

  • Vitali Zaidman
    Vitali Zaidman over 1 year

    I want to force the user to pass an es6 Map object to a React component using PropTypes, like this for example:

    static propTypes = {
      elementsMap: React.PropTypes.map(React.PropTypes.string, editorPropTypes.element).isRequired,
    }
    

    But looks like there is nothing like this in React. (The official documentation).

  • Vitali Zaidman
    Vitali Zaidman about 8 years
    And how do I specify an array of these for example, or a PropTypes.Shape with this proptype inside?
  • Brandon
    Brandon about 8 years
    Store that function as a variable (such as MyPropTypes.mapRequired) and just use MyPropTypes.mapRequired wherever you would use any other prop type like PropType.string.
  • Oleh
    Oleh almost 6 years
    but what about type of set's elements? Like we can do with an array prop arrayProp: PropTypes.arrayOf(PropType.string)
  • Eliran Malka
    Eliran Malka over 4 years
    what's p'? the PropTypes main module?
  • Анна
    Анна over 3 years
    p in this case is indeed the PropTypes main module, and instanceOf is an object that can be imported from prop-types. Thus, you could simply import it import { instanceOf } from 'prop-types'; and then use as propTypes: elementsMap: instanceOf(Map).isRequired