JS-1389 Fix FP in S6767: props reported unused when component wraps React.forwardRef#6591
Conversation
Tests cover the scenario where props are reported as unused when accessed via closure inside a React.forwardRef() or forwardRef() callback. The outer component's props are attributed to the inner forwardRef scope by the upstream rule, causing false positives. The tests verify: - React.forwardRef closure pattern is suppressed (FP) - Bare forwardRef closure pattern is suppressed (FP) - Suppression is component-scoped, not file-wide (TP in sibling component) - TypeScript interface-based props with React.forwardRef are suppressed - Upstream rule sentinel confirms the FP pattern still exists upstream Relates to JS-1389
When an outer function component passes props via closure into a nested React.forwardRef() or forwardRef() callback, the upstream no-unused-prop-types rule tracks prop usage per component scope boundary. It attributes props.label usage to the inner forwardRef scope rather than the outer component, causing false positives. The fix extends the S6767 decorator with a composable forwardRefCalleePatterns array and a containsForwardRefCall helper. After the existing hasPropsCall guard, a second component-scoped check suppresses the report when the owning component's subtree contains a forwardRef call. The suppression requires a non-null componentNode, ensuring only the affected component is suppressed and sibling components with genuine unused props are still reported. Implementation follows the approved proposal algorithm. Relates to JS-1389.
Ticket: JS-1389 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Ruling Report✅ No changes to ruling expected issues in this PR |
|
The current suppression fires for the entire component as soon as any A more precise approach: suppress only when the specific reported prop is actually referenced inside the
This way, props genuinely used via closure are suppressed, while props that are declared in |
Comment: The current suppression fires for the entire component as soon as any `forwardRef` call is found in its subtree, regardless of which specific prop was flagged. This can produce false negatives: a component that uses `forwardRef` internally but also has genuinely unused props declared in `propTypes` would have all its reports silenced. A more precise approach would be to suppress only when the specific reported prop name is actually referenced inside the `forwardRef` callback body (the lambda or function expression passed as the first argument). That way, props used via closure are suppressed, but props that are not referenced inside the callback are still reported correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
Good catch. The broad suppression was indeed a false-negative risk. The fix replaces
The prop name is extracted from A new invalid test case was added to cover the scenario described in the comment: a component with |
README Freshness Check❌ The rules README is out of date. A fix PR has been created: #6618 Please review and merge it into your branch. |
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
The new A more robust and efficient approach is to use ESLint's pre-built scope data instead:
This resolves both issues: the props parameter name is taken from the actual binding rather than assumed, and the reference list is O(1) to obtain since ESLint built it during its own traversal. |
s6767-props-reported-unused-when-component-is-wrapped-with-reactforwardref-sonnet
There was a problem hiding this comment.
Conclusion: Solid fix. The scope-based reference walk is precise (suppresses only the specific reported prop, not all props), conservative (rejects destructured params and computed member accesses), and correctly bounded (ancestor walk only matches when the member access is nested inside a forwardRef call, not just anywhere in the component). The sentinel test that verifies the upstream rule still raises the FP is a particularly good safety net.
s6767-props-reported-unused-when-component-is-wrapped-with-reactforwardref-sonnet
|
Both issues have been addressed in the latest commit (Use scope references for forwardRef prop suppression). The updated hasPropMemberReference implementation now:
The ancestor walk is now a short upward climb (isPropReferenceInForwardRefCallback walks parent nodes from the MemberExpression up to find the enclosing forwardRef call), not a downward subtree scan. A test case with the renamed 'ownProps' parameter was also added to confirm the fix handles non-default prop parameter names correctly. |
|
Thank you for the thorough review! |
|
Thank you for the review! |
|
Thank you for the review and approval! |
The ancestor walk in isPropReferenceInForwardRefCallback now tracks the previous node to confirm the reference sits specifically inside call.arguments[0] (the render callback), not in the callee position or a later argument of the forwardRef call. Also fixes a stale comment in unit.test.ts that still referenced the old containsForwardRefCall approach. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Good catch — the ancestor walk was finding any forwardRef CallExpression in the ancestry chain without verifying the reference sits inside its first argument specifically. I've updated Also fixed a stale comment in the TypeScript test that still referenced |
|
Thank you for the review! |
s6767-props-reported-unused-when-component-is-wrapped-with-reactforwardref-sonnet
|
|
Thank you for the review! |




Fixes a false positive in rule S6767 where props are incorrectly reported as unused when an outer function component passes props via closure into a nested
React.forwardRef()orforwardRef()callback.Root Cause
The upstream
no-unused-prop-typesrule tracks prop usage per component scope boundary. It attributesprops.labelusage to the innerforwardRefscope rather than the outer component, causing false positives in the S6767 decorator.Changes
forwardRefCalleePatternsarray and acontainsForwardRefCallhelperhasPropsCallguard, adds a component-scoped check that suppresses the report when the owning component's subtree contains aforwardRefcallcomponentNode, ensuring only the affected component is suppressed — sibling components with genuinely unused props are still reportedReact.forwardRefclosure pattern, bareforwardRefclosure pattern, component-scoped suppression (sibling TP still fires), and TypeScript interface-based props withReact.forwardRefRelates to JS-1389.