DEV Community

AidanMargo
AidanMargo

Posted on

Understanding React Proptypes

What is "Proptypes"

Proptypes is a react hook that makes debugging your programs a lot easier, namely when there's a conflict amongst data types.

You may remember Mousseboy if you've stopped by my page before. If not, here he is. We're gonna use him for our demonstration.

MousseBoy

Starter Code

Here's some really basic, unstyled react code that we're using for this example:

import Mousseboy from './Mousseboy'


function App() {
  return (
    <div className="App">
      <Mousseboy name='Mousseboy' age={'12'}/>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode
function Mousseboy ({name, age}) {
  return (
    <>
    <h3>{name} will be {age + 3} years old in 3 years!</h3>
    </>
    )}

export default Mousseboy
Enter fullscreen mode Exit fullscreen mode

What should we expect to see when we run this code? Since we passed the 'age' prop down with a value of 12, we would hope to see 15 come back to us, right?

Mousseboy 123

Not exactly! We passed down the age prop with a value of 12, but as a string. This causes the '3' to be tacked on to the end of the string '12.' He may be a grandpa, but he's not that old!

This is a really common bug that comes up, especially in large programs and applications. This is where proptypes comes in, to help us catch the issues when they arise.

Using Proptypes

First thing's first, we need to install the package so we can use it in our program. Run this code in the directory for your project:

$ npm i proptypes
Enter fullscreen mode Exit fullscreen mode

Assuming the install went as planned, you can now use the prop-types hook in your program! We're gonna use this in our "Mousseboy" component. Import "PropTypes" at the top of your component.

import PropTypes from 'prop-types'

And we're off! So prop-types is really great for catching unintended data-type errors in our code. Here's how we use it:

  1. call .proptypes on the component you're working in and set it to an object. It will need to be called after the return.
import PropTypes from 'prop-types'

function Mousseboy ({name, age}) {
  return (
    <>
    <h3>{name} will be {age + 3} years old in 3 years!</h3>

    </>
    )}

    Mousseboy.propTypes = {

    }
export default Mousseboy
Enter fullscreen mode Exit fullscreen mode
  1. We're going to need to add some keys and proptype values. Inside of our empty object, we're going to target the name and age props, and tell PropTypes what data type we're looking for.
    Mousseboy.propTypes = {
      name: PropTypes.string,
      age: PropTypes.number
    }
Enter fullscreen mode Exit fullscreen mode
  1. Now open up the devtools in your browser, and check out the error we get. Proptype error

Awesome! This error is letting us know that the age prop was passed down as a string, but we were expecting a number.

Tips and tricks

*There are a few ways we can use this on a bit of a deeper level. For example, if we were to remove the 'age' key from our .proptypes object, there would be no error!

To ensure we're notified of something not being passed down correctly, we can add .isRequired after our proptype(string, number, etc.)

I took out the age prop in our App component and added .isrequired to it in our proptype object. It looks like this:

Mousseboy.propTypes = {
      name: PropTypes.string,
      age: PropTypes.number.isRequired
    }
Enter fullscreen mode Exit fullscreen mode

And here is the error message we get:
age required

*We can use this with multiple datatypes! Here are a few examples:

  1. Proptypes.bool
  2. Proptypes.object
  3. Proptypes.symbol
  4. Proptypes.function
  5. Proptypes.any (rarely used, but if you do, add .isRequired !)
  • We can also add multiple options by using .oneOfType. Try this out:
Mousseboy.propTypes = {
      stringOrNumber: PropTypes.oneOfType ([
        Proptypes.string,
        Proptypes.number
      ]),
    }
Enter fullscreen mode Exit fullscreen mode

Make sure to update your passed props up in App!

Discussion (4)

Collapse
lukeshiru profile image
LUKESHIRU • Edited on

Worth mentioning that you can achieve a good DX without new dependencies using JSDocs:

// @ts-check

/** @type {import("react").VFC<{ name: string; age: number }>} */
export const Example = ({ name, age }) => (
    <h3>
        {name} will be {age + 3} years old in 3 years!
    </h3>
);
Enter fullscreen mode Exit fullscreen mode

If you try to use Example, you'll get autocompletion of name and age in your editor, if you try to pass a string to age it will give you an error, and it will also warn you if you didn't pass one of those required properties. If you want to make them optional, you can add question marks:

// @ts-check

/** @type {import("react").VFC<{ name?: string; age?: number }>} */
export const Example = ({ name, age }) => (
    <h3>
        {name} will be {age + 3} years old in 3 years!
    </h3>
);
Enter fullscreen mode Exit fullscreen mode

Also, you can achieve the same using TS instead of JS with JSDocs, like this:

import type { VFC } from "react";

export const Example: VFC<{ name?: string; age?: number }> = ({
    name,
    age
}) => (
    <h3>
        {name} will be {age + 3} years old in 3 years!
    </h3>
);
Enter fullscreen mode Exit fullscreen mode

The good thing about this approach is that:

  1. You'll get errors in dev, instead of having to reach that component to discover that something is wrong with it in production.
  2. You'll get a better experience in your editor.
  3. You don't need a new runtime dependency (better for the user and for you).

Cheers!

Collapse
aidanmargo profile image
AidanMargo Author

Thanks for this in depth explanation! I learned something this! Great stuff.

Collapse
sergeylukin profile image
Sergey Lukin

you nailed it!

Collapse
rajasekharguptha profile image
Rajasekhar Guptha

Nice 👍