From b7474504fe5b9101dd7f607d9bc71aa2e61dfb37 Mon Sep 17 00:00:00 2001 From: akulsr0 Date: Mon, 6 May 2024 14:13:56 +0530 Subject: [PATCH] [Fix] `prop-types`: fix `className` missing in prop validation false negative --- CHANGELOG.md | 6 ++++++ lib/util/propTypes.js | 19 +++++++++++++++++++ tests/lib/rules/prop-types.js | 23 +++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e7d214f0..5db11b6487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +### Fixed + +* [`prop-types`]: fix `className` missing in prop validation false negative ([#3749] @akulsr0) + +[#3749]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3749 + ## [7.34.3] - 2024.06.18 ### Fixed diff --git a/lib/util/propTypes.js b/lib/util/propTypes.js index 22063afb8e..84f5479f15 100644 --- a/lib/util/propTypes.js +++ b/lib/util/propTypes.js @@ -645,6 +645,17 @@ module.exports = function propTypesInstructions(context, components, utils) { this.shouldSpecifyOptionalChildrenProps = true; const rightMostName = getRightMostTypeName(node.typeName); + if ( + leftMostName === 'React' + && ( + rightMostName === 'HTMLAttributes' + || rightMostName === 'HTMLElement' + || rightMostName === 'HTMLProps' + ) + ) { + this.shouldSpecifyClassNameProp = true; + } + const importedName = localToImportedMap[rightMostName]; const idx = genericTypeParamIndexWherePropsArePresent[ leftMostName !== rightMostName ? rightMostName : importedName @@ -835,6 +846,14 @@ module.exports = function propTypesInstructions(context, components, utils) { isRequired: false, }; } + if (this.shouldSpecifyClassNameProp) { + this.declaredPropTypes.className = { + fullName: 'className', + name: 'className', + isRequired: false, + }; + } + this.foundDeclaredPropertiesList.forEach((tsInterfaceBody) => { if (tsInterfaceBody && (tsInterfaceBody.type === 'TSPropertySignature' || tsInterfaceBody.type === 'TSMethodSignature')) { let accessor = 'name'; diff --git a/tests/lib/rules/prop-types.js b/tests/lib/rules/prop-types.js index 97206b7d44..638861e2bb 100644 --- a/tests/lib/rules/prop-types.js +++ b/tests/lib/rules/prop-types.js @@ -4195,6 +4195,29 @@ ruleTester.run('prop-types', rule, { ); `, features: ['types'], + }, + { + code: ` + import React from "react" + + export function Heading({ className, ...props }: React.HTMLAttributes) { + return
+ } + `, + features: ['types'], + }, + { + code: ` + import React from 'react'; + type TDelIconProps = React.HTMLProps; + + const DelIcon: React.FC = ({className, ...rest}) => ( +
+ +
+ ); + `, + features: ['types'], } )),