eslint-plugin-react: Destructured use of property is not recognized by no-unused-prop-types

Given a React component like:

export default class Thing extends React.Component {
  static propTypes = {
    i18n: PropTypes.shape({
      gettext: PropTypes.func,
    }).isRequired,
  }

  render() {
    const { i18n } = this.props;

    return (
      <div>
        <span>{i18n.gettext('Some Text')}</span>
      </div>
    );
  }
}

And the following eslint rule:

"react/no-unused-prop-types": "error"

I see the following error:

/Users/kumar/tmp/eslint-scratch/index.js
  6:16  error  'i18n.gettext' PropType is defined but prop is never used  react/no-unused-prop-types

This is incorrect because the i18n property is destructured into a new constant and then the gettext() function is called. If I edit the code so that it doesn’t use destructuring then the error goes away, revealing the bug.

Here is a small app that reproduces it: eslint-scratch.zip. Run:

npm install
npm run eslint

This is similar to https://github.com/yannickcr/eslint-plugin-react/issues/782 but they seem different.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 48
  • Comments: 37 (14 by maintainers)

Commits related to this issue

Most upvoted comments

I am seeing this as well when using PropTypes.arrayOf(PropTypes.shape({...}) and then mapping the prop in render

I have a warning with flow too. My code:

type Props = {
  obj: {
    num: number, // < obj.num PropType is defined but prop is never used (react/no-unused-prop-types)
  },
};
...
static propTypes = {
  obj: PropTypes.shape({
    num: PropTypes.number, // < no error here
  }),
};

props: Props;
...
render() {
  const {obj: {num}} = this.props;
  return <div>{num}</div>;
}

And my solution:

type Props = {
  /* eslint-disable */
  obj: {
    num: number,
  },
  /* eslint-enable */
};

I can create a repro if it’s necessary.

@numbergames Warnings are valid, in this case.

const Component = ({ children: aNode }) => (
   // ...
);

// is equivalent of this

const Component = (props) => {
  const { children: aNode } = props;
  // ...
}

Thus, all prop validation does apply to original prop names - not aliased. Same applies to defaultProps

Correct usage would be:

import React from 'react';

const Component = ({ children: aNode }) => (
  <div>
    {aNode}
  </div>
);

Component.defaultProps = {
  children: null,
};

Component.propTypes = {
  children: React.PropTypes.node,
};

@ljharb I have created a PR with (what I think) all of the valid use cases discussed in this thread. Most of them are fixed already. I found only one reported by @robguy21, that needs to be investigated (I commented it out and will look into it). Please let me know if missed any other valid cases from this issue. Thanks!

It’s this kind of snark that I came here for. Thanks!