Back

How to forget about type errors in your React props with PropTypes

How to forget about type errors in your React props with PropTypes

Do you write or maintain code using React? Then you must be familiar with constant debugging that happens as you build and after you build an app. Do you want to reduce debug time drastically, then this post is for you. In this article, we will be looking at how to making your debugging process faster with prop types in React, what they are, how they are related to TypeScript, and how they are used with practical examples.

What are prop types

React prop type is a library supported by React that lets you define types for props in your components. Prototypes are a simple way of validating or ensuring that the data we pass from one component to another or from one element to another is the exact type of data we intend on passing. In React, one of the ways to pass data is through properties and so as you will see later in this post, it is important to check those types. Since React is a JavaScript framework and we know that it is dynamically typed, so property types in JavaScript are determined at runtime. Type checking is something TypeScript as a language is well known for and so you might wonder how they relate with React prop types.

As your application gets bigger and bigger the chances of having more bugs increase, knowing that you can catch a lot of them easily through type-checking is a great thing. With Proptypes, whether or not you are writing, reading, or maintaining a codebase the components will always be predictable for you.

How it relates to TypeScript

TypeScript is a statically typed version of JavaScript which solves the dynamic typing issues around knowing or enforcing types for not just properties but for almost everything else in JavaScript. However, with TypeScript, the types are checked at compile time which means that as you write your code you get the warnings in real-time. With Proptypes, these checks happen at runtime and so are focused on component interaction and debugging. Using prop types in React gives you a bit of the TypeScript experience at runtime without having to use TypeScript.

The problem

The interesting use case here is how you can pass in any type of data and it compiles without any warnings in React. This can be very costly as it becomes tough to notice while debugging and most of the time these are the kinds of things that the user of the application first notices.

What we will be building

How does your component look without prop types? Let us find out with this demo below

demo gif

This is a simple car list displayed in a card-like form, if you followed this post from the start you must have created the “propstest” project which we will be using throughout this tutorial. Navigate to a folder of your choice and open that in VS Code, run the command below in the terminal:

npx create-react-app propstest

Inside the source folder create a components folder and then a functional component file, call it Car.js and copy this code block below inside it:

import React from "react"
const Car = (prop) => {
    return ( <div className = "container responsive" >
        <div className = "car" >
          <h2 > This {prop.brand} {prop.model
          } < /h2> 
          <h4 > has a millage of {prop.milage} < /h4> 
          <h4 > It is an electric vehicle - {prop.isElectric} < /h4> 
          <ul > {
              prop.owners.map((owner, key) => {
                  return <li key = {key} > {owner} < /li>;
              })
          } 
          </ul> 
          </div> 
        </div>
    );
};
export default Car;

This is a simple functional component that renders and export Car template with some headers and a list. Inside the source folder, you can see the app component (App.js) file, copy the code block below into the app.js file:

import './App.css';
import Car from './Components/Car'

function App() {
    return ( <div className = "App" >
        <Car brand = "Tesla"
          model = "CyberTruck"
          milage = {5000}
          isElectric = {"true"}
          owners = {["Lotanna"]}
        /> 
        <Car brand = "Ford"
          model = "Explorer"
          milage = {8000}
          isElectric = {"false"}
          owners = {["Runor", "Elijah"]}
        /> 
        <Car brand = "Benz"
          model = "CLA250"
          milage = {7500}
          isElectric = {"false"}
          owners = {["Gilbert", "Herbert", "Frank", "Mazior"]}
        /> 
        <Car brand = "Toyota"
          model = "Camry"
          milage = {3000}
          isElectric = {"false"}
          owners = {["Ebuka", "Ikenna", "Ekene"]}
        /> 
        </div >
    );
}
export default App;

Here we are bringing in the defined templates and telling React to render it four times with our own pre-defined properties. These properties include the car brand, the model, mileage, and the owners of the car. When you run the dev server command:

npm start

You will see information all scattered, adding a little CSS rule to make it look presentable, navigate to the app.css file and copy these styles below:

.App {
    text-align: center;
}

.container {
    position: relative;
}

ul {
    list-style-type: none;
    text-align: center;
}

.car {
    top: 50%;
    text-align: center;
    border-radius: 25px;
    border: 2px solid #73AD21;
    padding: 20px;
    width: 600px;
    height: 250px;
    margin-left: 25%;
    margin-bottom: 15px;
}

Running the dev server command again, you will notice in your browser at http: //localhost:3000/ that it looks exactly like the demo gif we have above. Now we can go into the app component file and change the Tesla string to a number, say 5000 and the milage to Rabbit, the application still runs fine without an error or warning at all.

Things like this can be very hard to catch during a debugging session, it can happen through human error, direct user input or data from another component or API especially if you are not the author of the codebase. We can go even further to change the owner’s side from an array containing “lotanna” to just a string.

The app crashes on compile, but not because of the type, only because we have a map function for the owners, and the map only works on a list (in our case, an array) ## Solution: prop types A great solution to this problem is to define the types for every prop you want to use. The Syntax of prop types looks like this in a functional component:

import PropTypes from 'prop-types'

function HelloWorldComponent( {name}) {
    return (<div>Hello, {name} </div>)
}

HelloWorldComponent.propTypes = {
    name: PropTypes.string
}

export default HelloWorldComponent

Let us see how it works in our app, start by installing the prop types package inside your project with this command:

npm install proptypes

Inside the component you want to define the types, import the installed prop types, in our case inside the Car.js file:

import React from "react"
import PropTypes from "prop-types"
const Car = (prop) => {
    return ( <
        div className = "container responsive" >
        <div className = "car" >
          <h2> This {prop.brand } { prop.model } < /h2> 
          <h4> has a millage of { prop.milage } < /h4> 
          <h4 > It is an electric vehicle - { prop.isElectric } </h4> 
          <ul> {
              prop.owners.map((owner, key) => {
                  return <li key = {key} > {owner} < /li>;
              })
          } 
          </ul> 
          </div> 
        </div>
    );
};
Car.propTypes = {
    brand: PropTypes.string,
    model: PropTypes.string,
    milage: PropTypes.number,
    isElectric: PropTypes.string,
    owners: PropTypes.arrayOf(PropTypes.node)
}
export default Car;

Notice the prop types being defined before the export of the component, that is very important because if you export before defining the prop types, it would not work in the dev server.

This reminds me so much of form validator libraries, they are basically structured like this as well. We added a few prop types in this Car component and some of them are:

  • Proptype.string: This defines the type of prop required here is of type string.
  • Proptype.number: This defines the needed type of prop here to be type number.
  • Proptype.arrayOf: This defines the type of prop required here to be an array type, inside which you can now specify exactly the type of the children.
  • Proptype.node: This defines the type of anything that can be rendered in the UI. That includes numbers, strings, elements, an array, or even fragments.

There are other types you can read about in the documentation here.

Testing the prop types

Now if you run the application in your dev server you will see that everything runs perfectly however when you try to change Tesla to a number the application still runs but this time it shows a warning in the console.

These warnings are very descriptive that once you read them you know exactly what has gone wrong and what to fix.

More use cases: OneOf example

It gets even more interesting, with oneOf you can specify the exact value you want from your props so no matter where the data source is, if it does not match your specifications you would get the warning. Let us define exact values in the Car component like this:

import React from "react"
import PropTypes from "prop-types"
const Car = (prop) => {
    return ( <div className = "container responsive" >
        <div className = "car" >
          <h2 > This { prop.brand } { prop.model } < /h2> 
          <h4 > has a millage of { prop.milage } < /h4> 
          <h4 > It is an electric vehicle - { prop.isElectric } < /h4> 
          <ul> { prop.owners.map((owner, key) => {
                  return <li key = { key } > { owner } < /li>;
              })
          } 
          </ul> 
          </div> 
        </div>
    );
};
Car.propTypes = {
    brand: PropTypes.oneOf(['Ford', 'Benz', 'Toyota']),
    model: PropTypes.string,
    milage: PropTypes.number,
    isElectric: PropTypes.string,
    owners: PropTypes.arrayOf(PropTypes.node)
}
export default Car;

You can see we specified the exact values we needed and I purposely omitted Tesla and so when we run the app again, here is the warning we get.

Prop types in class components

Prop types also work well in React class components, let us quickly create one class component. Open the components folder and create a new component file, call it Sample.js , and inside it copy the code block below:

import React from "react"
import PropTypes from 'prop-types';
class Greeting extends React.Component {
    render() {
        return ( <h1 > Hello, { this.props.brand } < /h1>
        );
    }
}
Greeting.propTypes = {
    brand: PropTypes.string
};
export default Greeting;

Inside the app component file (App.js) import Greeting and add the corresponding template like this:

import './App.css';
import Car from './Components/Car'
import Greeting from './Components/Sample'

function App() {
    return ( <
        div className = "App" >
        <Greeting brand = "Reader" />
        <Car brand = { 4555 }
          model = "CyberTruck"
          milage = { 5000 }
          isElectric = { "true" }
          owners = { ["Lotanna"] }
        /> 
        <Car brand = "Ford"
          model = "Explorer"
          milage = { 8000 }
          isElectric = { "false" }
          owners = { ["Runor", "Elijah", 3] }
        /> 
        <Car brand = "Benz"
          model = "CLA250"
          milage = {7500}
          isElectric = { "false" }
          owners = { ["Gilbert", "Herbert", "Frank", "Mazior"] }
        /> 
        <Car brand = "Toyota"
          model = "Camry"
          milage = { 3000 }
          isElectric = { "false" }
          owners = { ["Ebuka", "Ikenna", "Ekene"] }
        /> 
        < /div >
    );
}
export default App;

When you run it in the dev server you can see it shows up like this:

Open Source Session Replay

OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.

replayer.png

Start enjoying your debugging experience - start using OpenReplay for free.

Wrapping up

In this tutorial, we have taken a look at prop types in React, why they are important and how they can be relatable to TypeScript. We also took a look at how they are used with various examples and a working demo. I hope you would adopt prop types going forward to make debugging and maintaining your code easier. Happy hacking!