React: Cannot mark a prop as `isRequired` when using custom propTypes validation

Created on 6 Mar 2017  路  3Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?

bug, or missing feature rather, that should be there

What is the current behavior?

I can't define a prop as isRequired when using custom validation

Simple stateless component that demonstrates the issue

const Component = ({ content }) => <div>{content}</div>

Component.propTypes = {
  content: (props, propName, componentName) => {
    if (props.content === "I'll allow it!") {
      return null;
    }

    return new Error(`Content ${content} is not allowed!`);
  }
}

What is the expected behavior?

I can, somehow, define a prop as required after

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

  • React 15+
  • I don't think it ever worked, but might be that is just some black sorcery needed

In the simplified example I posted, I couldn't find any way of adding isRequired to that prop, either by adding it at the end of the function, abstracting the validation function away, or even returning this to chain it (it has to return null or an Error).

Most helpful comment

Hi! It seems like you're under the impression that isRequired is something that React adds to your prop types at runtime, but it's really just a convention that the built-in prop types all support. If you want this functionality in your custom prop types, you have to add that yourself.

Here's an example of how you can add isRequired to your own custom validators:

// This is a factory function (also called a higher-order function)
function createCustomPropType(isRequired) {
  // The factory returns a custom prop type
  return function(props, propName, componentName) {
    const prop = props[propName];
    if (prop == null) {
      // Prop is missing
      if (isRequired) {
        // Prop is required but wasn't specified. Throw an error.
        throw new Error();
      }
      // Prop is optional. Do nothing.
    } else {
      // Put your validation logic here...
    }
  }
}

// Using the factory, create two different versions of your prop type
const customPropType = createCustomPropType(false);
customPropType.isRequired = createCustomPropType(true);

// Now this will work:
MyComponent.propTypes = {
  optional: customPropType,
  required: customPropType.isRequired,
};

This is essentially how React's built-in prop types do it, too: https://github.com/facebook/react/blob/master/src/isomorphic/classic/types/ReactPropTypes.js#L157-L223

Hope that helps!

All 3 comments

Hi! It seems like you're under the impression that isRequired is something that React adds to your prop types at runtime, but it's really just a convention that the built-in prop types all support. If you want this functionality in your custom prop types, you have to add that yourself.

Here's an example of how you can add isRequired to your own custom validators:

// This is a factory function (also called a higher-order function)
function createCustomPropType(isRequired) {
  // The factory returns a custom prop type
  return function(props, propName, componentName) {
    const prop = props[propName];
    if (prop == null) {
      // Prop is missing
      if (isRequired) {
        // Prop is required but wasn't specified. Throw an error.
        throw new Error();
      }
      // Prop is optional. Do nothing.
    } else {
      // Put your validation logic here...
    }
  }
}

// Using the factory, create two different versions of your prop type
const customPropType = createCustomPropType(false);
customPropType.isRequired = createCustomPropType(true);

// Now this will work:
MyComponent.propTypes = {
  optional: customPropType,
  required: customPropType.isRequired,
};

This is essentially how React's built-in prop types do it, too: https://github.com/facebook/react/blob/master/src/isomorphic/classic/types/ReactPropTypes.js#L157-L223

Hope that helps!

Thanks @acdlite, this is exactly what I was looking for, and you're right, I was under the impression that React was doing some sort of runtime analysis on those isRequired tidbits.

I think it's worthwhile to update the docs on this regard with the example you posted, or something along the lines. What do you think?

@acdlite thanks, works perfectly for me : )

Was this page helpful?
0 / 5 - 0 ratings