Web Dev Simplified Blog

How To Use PropTypes In React

December 21, 2020

If you have ever wanted to add type safety to your React projects, but bringing in TypeScript is too overkill or too much work then PropTypes is perfect for you. PropTypes is a tool in React that lets you validate the structure and type of all your props and if there are any issues they will show up as errors in the console of your browser dev tools.

Getting Started

In order to start using PropTypes in your project you need to install the PropTypes library.

npm i prop-types

Previously PropTypes was included with React by default, but now it is in its own library which is why we must install it separately. Once you have PropTypes installed you can start using it immediately.

It doesn’t matter if you are working with a class or function component, setting up PropTypes works exactly the same. You just need to define a property on the class/function called propTypes. This property will be an object that outlines all the props for the component.

import PropTypes from 'prop-types'

class Component {
  render() {
    return 'Hi'
  }
}

Component.propTypes = {
  // Put props here
}

export default Component
import PropTypes from 'prop-types'

function Component(props) {
  return 'Hi'
}

Component.propTypes = {
  // Put props here
}

export default Component

Since defining PropTypes on a component does not depend on the component implementation we will be leaving out the code for the component itself in all the following examples. The code above will be simplified to the following.

Component.propTypes = {
  // Put props here
}

Checking Basic Types

The most basic way you can check a prop’s type is by checking to see if it is one of the primitive types in JavaScript, such as a boolean, string, object, etc. In order to do this we would use the name of the prop as the key in the propTypes object and the value for that key will be the specific PropType we are checking.

Component.propTypes = {
  name: PropTypes.string,
  age: PropTypes.number,
  address: PropTypes.object,
  friends: PropTypes.array
}

In the above code we are saying that we expect the name prop of the Component to be of the type string. We also expect the age prop to be a number, the address prop to be an object, and the friends prop to be an array.

This is the easiest way to setup PropTypes and is great for catching minor errors, such as, accidentally passing a string instead of a number.

<Component name="Kyle" age="25" />

If we create a component with the following code we will get a warning in the console.

Warning: Failed prop type: Invalid prop age of type string supplied to Component, expected number.

This is great since we can now guarantee that the age prop is always a number. You will also notice that there are no warnings for missing props even though we defined PropTypes for address and friends. This is because by default all props are optional. In order to make a prop required we can chain isRequired to the end of the PropType.

Component.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  address: PropTypes.object.isRequired,
  friends: PropTypes.array
}

With the above code we have marked our name, age, and address props as required which means now if we do not pass an address for example we will get the following error.

Warning: Failed prop type: The prop address is marked as required in Component, but its value is undefined

Also, here is a list of all the basic PropTypes for checking JavaScript primitives

PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.symbol

React Specific Prop Types

On top of being able to check primitive types, you can also check some React specific things as well.

Checking For Renderability

If you want to simply check to see if a component can be rendered you can use the PropTypes.node check. This will check to see if the prop is a type that React can render. Things such as strings, numbers, elements, and arrays are common renderable types.

Component.propTypes = {
  renderableProp: PropTypes.node
}

Checking For A React Component

If you want to just check to see if a prop is a React component you can use PropTypes.element. This is useful for ensuring that a component only ever has one child component, for example.

Component.propTypes = {
  children: PropTypes.element.isRequired
}

Checking For A React Component Name

Finally, you can check to see if your prop is the name of a React component by using PropTypes.elementType.

Component.propTypes = {
  as: PropTypes.elementType
}
<AnotherComponent as={Component} />

Advanced Type Checking

PropTypes also contain a ton of different advanced type checking techniques.

Checking For Any Type

Sometimes you just want to ensure a prop is required without specifying a specific type. This is where PropTypes.any comes in handy since it will never throw a warning for the type.

Component.propTypes = {
  couldBeAnything: PropTypes.any.isRequired
}

Checking For Multiple Types

If you don’t like the idea of using any, but also have a prop that could be multiple types you can use PropTypes.oneOfType() to specify which types the prop can be. This just takes an array of valid PropTypes.

Component.propTypes = {
  stringOrNumber: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number
  ])
}

Creating An Enum

If you want to ensure that a prop’s value is from a specific list you can use PropTypes.oneOf() to define the allowed values. This is perfect for creating an enum.

Component.propTypes = {
  state: PropTypes.oneOf([
    'LOADING',
    'READY',
    'ERROR'
  ])
}

Checking Array Types

When you have an array where you know the type of the elements, you can use PropTypes.arrayOf() to specify the type of the elements. This works very similar to PropTypes.array, but it also type checks the elements in the array as well.

Component.propTypes = {
  names: PropTypes.arrayOf(PropTypes.string)
}

Checking Object Types

Just like with arrays, you can also check the types of the individual properties of an object with PropTypes.shape(). This is really useful when passing large objects down to a component.

Component.propTypes = {
  address: PropTypes.shape({
    street: PropTypes.string.isRequired,
    state: PropTypes.string,
    country: PropTypes.oneOf(['US', 'India']).isRequired
  })
}

This above code will only throw a warning if one of the specified properties of address does not follow its PropType. If address has additional properties on it, such as as zip code, that will not cause any warnings. If you did want to throw a warning, though, when the object has properties not specified in the PropTypes you could use PropTypes.exact() instead. It works exactly the same as PropTypes.shape(), but it will throw a warning if the object has properties not defined in the PropTypes.

Component.propTypes = {
  address: PropTypes.exact({
    street: PropTypes.string.isRequired,
    state: PropTypes.string,
    country: PropTypes.oneOf(['US', 'India']).isRequired
  })
}

Conclusion

PropTypes are a great way to add a first line of defense in you applications. It isn’t perfect, though, as it will only catch errors at runtime, while something like TypeScript will catch these errors in the compilation step, but it is much easier to setup and work with.


Kyle Cook
Kyle Cook