Accessing React PropTypes Meta-Data

When developing a new React component, you can pass it any property and access it without having to declare it. But one important feature of React is the declaration of PropTypes.

PropTypes allow you to define the interface of your React component, specifying which properties you accept, and their types. This mechanism also allows you to distinguish between required and optional properties.

This mechanism has two purposes, the first is to be used by React during debug to validate the properties you are passing to your components runtime. The second, and maybe the most important, is to let your components have an explicitly declared interface which can be used as self-documentation, improving theirs reusability.

Although these are the two main purposes of PropTypes, you can imagine other interesting cases in which you could use them. For example, if you are somehow integrating React Javascript components with a statically typed language, you may want to generate wrappers for these components. That is what I did to generate Java Vaadin wrappers for React components.

Extracting PropTypes Data from Components Source Code

Building tools that consume the component’s interface may not be trivial. One approach would be to read this interface based on the source code. That is the approach used by the official tool, react-docgen. This tool processes the Javascript code AST to read the PropTypes. Unfortunately the tool is very limited due to complexity of the problem. It is able to read trivial cases, for example, when the proptypes are inlined in the component:

React.createClass({
   propTypes : {
      //inlined proptypes
   }
});

React-docgen starts showing its limitations when the PropTypes are not declared inline.

var myComponent = React.createClass({});
myComponent.propTypes = require("./myComponentProps");

In this case the PropTypes are still valid for the React runtime, and a user can easily find them on the source code, but react-docgen is not able to find them.

The tool could probably be adapted to handle these cases but, due to the freedom of the Javascript language, dozens of different valid cases may exist, and adapting the tool to each case would require too much effort.

Notice that this is a known limitation of the tool contributors, and its documentation specifies that only components following certain code styles are supported.

Extracting PropTypes Data from Components Runtime

Since the Javascript code style freedom prevents us from reading the components meta-data from the source code, another approach is to access the component data through its runtime.

We could simply ‘require’ the component, and access its properties

var componentClass = require(componentFilePath);
//Process componentClass.propTypes

Unfortunatelly, the PropTypes are functions which are used by react to validate the objects, and these functions do not contain properties which allow us to extract the component meta-data.

Replacing React PropTypes with Reflective PropTypes

To solve the problem of PropTypes not holding their meta-information, we can replace React’s current PropTypes implementation with a new implementation, which instead of returing the validation functions, returns objects in the following format:

  • Type : The type of the property (string, number, etc..)
  • Required : True if the property is required
  • Inner : Extra information for complex types (e.g oneOf, ArrayOf, etc).

An implementation of such PropTypes can be seen in the vaadin-react project.

This script changes the React object which is shared by all the components, and by running it (through ‘require’) before we load the components, we ensure that they will use our custom PropTypes.

If you want to use this approach in your tool, you need to be sure that you are loading the React which is in the component scope. Notice in the script code that we are “requiring” react through its full path. We need to do this since the script is running in the “node” scope of another project, not in the component’s “node” scope.

Notice that this script is not generating “real” PropTypes, you should not be using it in a running React application. But if you want to, it can be easily adapted to delegate its validation behaviour to the original implementation.


❤ this story if you think it can be helpfull to your work!

Seeing any way of improving this process? Please comment bellow!