Skip to content

Commit 9af8845

Browse files
avaiceljharb
authored andcommitted
[Fix] no-unused-prop-types: detect used props in nested components
1 parent 6a42bc9 commit 9af8845

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
2323
* [`jsx-key`]: detect missing keys in return statement with ternary operator ([#3928][] @hyeonbinHur)
2424
* [`jsx-key`]: detect missing keys in logical expressions ([#3986][] @yalperg)
2525
* [`display-name`]: avoid false positive when React is shadowed ([#3926][] @hyeonbinHur)
26+
* [`no-unused-prop-types`]: detect used props in nested components ([#3955][] @avaice)
2627

2728
### Changed
2829
* [Docs] [`no-array-index-key`]: add template literal examples ([#3978][] @akahoshi1421)
@@ -32,6 +33,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
3233
[#3958]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3958
3334
[#3980]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3980
3435
[#3965]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3965
36+
[#3955]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3955
3537
[#3950]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3950
3638
[#3943]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3943
3739
[#3942]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3942

lib/util/usedPropTypes.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,20 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
407407
}
408408
}
409409

410-
components.set(component ? component.node : node, {
410+
let targetNode = component ? component.node : node;
411+
412+
if (component && !component.declaredPropTypes) {
413+
let parentComponent = components.get(node.parent);
414+
while (parentComponent) {
415+
if (parentComponent.declaredPropTypes) {
416+
targetNode = parentComponent.node;
417+
break;
418+
}
419+
parentComponent = components.get(parentComponent.parent);
420+
}
421+
}
422+
423+
components.set(targetNode, {
411424
usedPropTypes,
412425
ignoreUnusedPropTypesValidation,
413426
});

tests/lib/rules/no-unused-prop-types.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3948,6 +3948,34 @@ ruleTester.run('no-unused-prop-types', rule, {
39483948
`,
39493949
features: ['types'],
39503950
},
3951+
{
3952+
code: `
3953+
type Props = {
3954+
used: string;
3955+
};
3956+
3957+
const Demo = React.memo<Props>(
3958+
React.forwardRef<HTMLDivElement, Props>(
3959+
({ used }, ref) => {
3960+
return <div>{used}</div>
3961+
}
3962+
)
3963+
);
3964+
`,
3965+
features: ['types'],
3966+
},
3967+
{
3968+
code: `
3969+
const Demo = React.memo(
3970+
React.forwardRef(({ used }, ref) => {
3971+
return <div ref={ref}>{used}</div>
3972+
})
3973+
);
3974+
Demo.propTypes = {
3975+
used: PropTypes.string,
3976+
};
3977+
`,
3978+
},
39513979
]),
39523980

39533981
invalid: parsers.all([].concat(
@@ -6709,6 +6737,42 @@ ruleTester.run('no-unused-prop-types', rule, {
67096737
errors: [
67106738
{ message: '\'bar\' PropType is defined but prop is never used' },
67116739
],
6740+
},
6741+
{
6742+
code: `
6743+
type Props = {
6744+
used: string;
6745+
unused: string;
6746+
};
6747+
6748+
const Demo = React.memo<Props>(
6749+
React.forwardRef<HTMLDivElement, Props>(
6750+
({ used }, ref) => {
6751+
return <div>{used}</div>
6752+
}
6753+
)
6754+
);
6755+
`,
6756+
features: ['ts', 'no-babel'],
6757+
errors: [
6758+
{ message: '\'unused\' PropType is defined but prop is never used' },
6759+
],
6760+
},
6761+
{
6762+
code: `
6763+
const Demo = React.memo(
6764+
React.forwardRef(({ used }, ref) => {
6765+
return <div ref={ref}>{used}</div>
6766+
})
6767+
);
6768+
Demo.propTypes = {
6769+
used: PropTypes.string,
6770+
unused: PropTypes.string,
6771+
};
6772+
`,
6773+
errors: [
6774+
{ message: '\'unused\' PropType is defined but prop is never used' },
6775+
],
67126776
}
67136777
)),
67146778
});

0 commit comments

Comments
 (0)