Search code examples
javascriptreactjsreact-proptypes

If I add PropTypes, do I need to check typeof?


I have a prop onNotifyChange which is a function and I call it in the onChange of an input.

And it has a PropType for func.

MyComponent.propTypes = {
    onNotifyChange: PropTypes.func,
}

When calling onNotifyChange, do I need to check typeof

const onChange = e => {
    // do some stuff
    if(onNotifyChange && typeof onNotifyChange === 'function'){
        onNotifyChange()
    }
}

or just checking if it's falsy?

const onChange = e => {
    // do some stuff
    if(onNotifyChange){
        onNotifyChange()
    }
}

Does PropTypes.bar removes the need for checking typeof foo === 'bar'?


Solution

  • Yes you need to check the types of your props even when using prop-types. The prop-types library gives you runtime warnings in the development mode of React.

    In the example below we are using the development build of React. We have a component H1 with required function prop. Notice when using the H1 component within App, without passing a value for the className prop, an error is thrown, and prop-types has logged a warning.

    So, you cannot rely on prop-types to prevent bad props being passed down to children.

    function H1({ className, children }) {
      // this will throw if className is not a function
      return <h1 className={className()}>{children}</h1>
    }
    
    H1.propTypes = {
      className: PropTypes.func.required
    } 
    
    function App() {
      return <H1>Test</H1>
    }
    
    ReactDOM.render(<App />, document.querySelector("#root"))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.development.js"></script>
    <div id=root></div>

    To prevent this kind of thing happening at runtime you can:

    • declare a default value for the prop
    • do validation on the value of the prop within the component

    Even better, you can do both, as in the example below:

    function H1({ className, children }) {
      /* do some validation of your props 
         (throwing here to demonstrate that the default prop set below 
         works - I do not recommend throwing errors within components
         like this unless you know what you're doing, e.g. have an error
         boundary to catch behaviour like this) */
      if (typeof className !== "function") {
        throw new Error("expecting className prop to be function")
      }
      return <h1 className={className()}>{children}</h1>
    }
    
    H1.propTypes = {
      className: PropTypes.func.required
    } 
    
    H1.defaultProps = {
      className: () => ""
    }
    
    function App() {
      return <H1>Test</H1>
    }
    
    ReactDOM.render(<App />, document.querySelector("#root"))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.development.js"></script>
    <div id=root></div>

    This way your application will not crash due to a bad prop value, and in development mode you will see the warning logged by prop-types.