Master PropTypes in React

A useful guide to React propTypes and type checking

Sukhjinder Arora
Bits and Pieces

--

React is a JavaScript library for building user interfaces. React makes it easier to manage the state of our application and efficiently updates the UI when the state changes.

React is component based and each component can have its own state (manipulated via setState()) and can receive props (provided by the parent component).

Tip: Build React apps faster with reusable components. Use Bit to collect reusable components, share them with your team, and use them anywhere. Give it a try.

React spinner components with Bit: Choose, try, use.

The Problem

Since React is a JavaScript library and JavaScript does not provide any type-checking, passing the wrong type of props to components can cause a lot of bugs in your application.

Solution

You can use JavaScript extensions like TypeScript for type checking, but if you don’t want to use it, React provides useful type-checking features to verify that components receive props of the correct type. Using PropTypes, we can make sure that components receive the right type of props.

For example, suppose we have a Person component which receives two props: name and age of the person. Using PropTypes, we can ensure that name is always a string and the age is always a number.

Installing PropTypes

To use PropTypes, we have to install a separate prop-types package provided by React. For example:

npm install --save prop-types

OR

yarn add prop-types

Using PropTypes

To use PropTypes, we first have to import PropTypes from the prop-types package. For example:

import { PropTypes } from 'prop-types';

We can then define the propTypes property on a component. For example:

MyComponent.propTypes = {}; 

Here propTypes is an object which contains key-value pairs, where the key is the name of the prop and the value is the type of the prop that can be passed to the component.

Example

If we have a Student component which receives 2 props: 1) name of the student, and 2) age of the student.

import React from 'react';
import { PropTypes } from 'prop-types';
class Student extends React.Component {

render() {
return (
<div>
<p>Name: {this.props.name}</p>
<p>Age: {this.props.age}</p>
</div>
);
}
}

Using PropTypes, we can make sure that name is always a string, and age is always a number.

For example:

import React from 'react';
import { PropTypes } from 'prop-types';
class Student extends React.Component {

render() {
return (
<div>
<p>Student Name: {this.props.name}</p>
<p>Age: {this.props.age}</p>
</div>
);
}
}
Student.propTypes = {
name: PropTypes.string,
age: PropTypes.number
};
export default Student;

Here PropTypes.string and PropTypes.number are prop validators which can be used to make sure props received are of the right type. PropTypes has lots of validators, some of the most common use prop validators are:

MyComponent.propTypes = {
propArray: PropTypes.array,
propBool: PropTypes.bool,
propFunc: PropTypes.func,
propNumber: PropTypes.number,
propObject: PropTypes.object,
propString: PropTypes.string,
}

Passing Wrong Props

When a wrong or invalid prop is passed to the component, a warning or an error is shown in the JavaScript Console. For example:

import React from 'react';
import Student from './Student';
class App extends React.Component { render() {
return (
<div>
<Student name="Mark" age="24" />
</div>
);
}
}
export default App;

Here the age prop is passed as a string to the Student component. So React will show a warning in the JavaScript console. For example:

PropTypes in Class Components

There is no difference between using PropTypes in class-based components versus functional components. For example:

import React from 'react';
import { PropTypes } from 'prop-types';
class Student extends React.Component {

render() {
return (
<div>
<p>Student Name: {this.props.name}</p>
<p>Age: {this.props.age}</p>
</div>
);
}
}
Student.propTypes = {
name: PropTypes.string,
age: PropTypes.number
};
export default Student;

PropTypes in Functional Components

import React from 'react';
import { PropTypes } from 'prop-types';
const Student = (props) => {
return (
<div>
<p>Student Name: {props.name}</p>
<p>Age: {props.age}</p>
</div>
);
};
Student.propTypes = {
name: PropTypes.string,
age: PropTypes.number
};
export default Student;

Requiring Props

Apart from specifying the type of the prop that can be passed to the component, we can also make sure the prop is always provided to the component by chaining isRequired at the end of the prop validator.For example:

import React from 'react';
import { PropTypes } from 'prop-types';
class Student extends React.Component {

render() {
return (
<div>
<p>Student Name: {this.props.name}</p>
<p>Age: {this.props.age}</p>
</div>
);
}
}
Student.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number
};
export default Student;

A warning will be shown to the console if the name prop is not provided to the Student component. For example:

import React from 'react';
import Student from './Student';
class App extends React.Component {render() {
return (
<div>
<Student age="24" />
</div>
);
}
}
export default App;

Here the name prop is not passed to the component, so React will display a warning. For example:

Requiring Single Child

We can use PropTypes.element to enforce that only a single child can be passed to a component as children. For example:

import React from 'react';
import { PropTypes } from 'prop-types';
class Container extends React.Component {render() {
return (
<div>
{this.props.children}
</div>
);
}
}
Container.propTypes = {
children: PropTypes.element
};
export default Container;

If we try to pass more than 1 child to the component, we will get an error. For example:

import React from 'react';
import Container from './Container';
import Student from './Student';
class App extends React.Component {render() {
return (
<div>
<Container>
<Student name="Mark" age="24" />
<Student name="Peter" age="25" />
</Container>
</div>
);
}
}
export default App;

Advance PropTypes Validators

Apart from specifying whether a prop should be an array or an object, we can use these prop validators to specify which type of array or object can be passed as a prop. For example:

PropTypes.arrayOf()

We can use PropTypes.arrayOf() to specify which type of array can be passed as a prop. For example:

import React from 'react';
import { PropTypes } from 'prop-types';
class Numbers extends React.Component {

render() {
const numbers = this.props.numbers.map(number => <p>{number}</p>);
return (
<div>
{numbers}
</div>
);
}
}
Numbers.propTypes = {
numbers: PropTypes.arrayOf(PropTypes.number)
};
export default Numbers;

Here only an array of number type can be passed as a prop. If we try to pass wrong type of array as a prop, we’d get a warning. For example:

import React from 'react';
import Numbers from './Numbers';
class App extends React.Component {render() {
return (
<div>
<Numbers numbers={['1', '2', '3']} />
</div>
);
}
}
export default App;

PropTypes.objectOf()

Similar to PropTypes.arrayOf() we can use PropTypes.objectOf() to specify which type of object can be passed as a prop to the component. For example:

NamesList.propTypes = {
names: PropTypes.objectOf(PropTypes.string)
}

Here, the only object which contains string type values can be passed as a prop to the component.

Conclusion

We have learned what PropTypes are and how to use them for type-checking. While you may not find type-checking useful for small applications, it can avoid a lot of bugs if your application is fairly large.

That’s it and I hope you found this article helpful. If you have any questions, please feel free to comment! I’d be happy to help :) You can also follow me on Medium and Twitter. Thanks for reading! 😃

--

--