Skip to content

Commit a771125

Browse files
committed
Add similar supprt for no-used-prop-types
1 parent 87aca04 commit a771125

File tree

2 files changed

+96
-18
lines changed

2 files changed

+96
-18
lines changed

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

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,50 @@ module.exports = {
724724
});
725725
}
726726

727+
/**
728+
* Marks all props found inside IntersectionTypeAnnotation as declared.
729+
* Since InterSectionTypeAnnotations can be nested, this handles recursively.
730+
*
731+
* Modifies the declaredPropTypes object
732+
* @param {ASTNode} propTypes
733+
* @param {Object} declaredPropTypes
734+
* @returns {Boolean} True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
735+
*/
736+
function declarePropTypesForIntersectionTypeAnnotation(propTypes, declaredPropTypes) {
737+
let ignorePropsValidation = false;
738+
739+
propTypes.types.forEach(annotation => {
740+
const typeNode = typeScope(annotation.id.name);
741+
742+
if (!typeNode) {
743+
ignorePropsValidation = true;
744+
return;
745+
}
746+
747+
if (typeNode.type === 'IntersectionTypeAnnotation') {
748+
ignorePropsValidation = declarePropTypesForIntersectionTypeAnnotation(typeNode, declaredPropTypes);
749+
} else {
750+
iterateProperties(typeNode.properties, (key, value) => {
751+
if (!value) {
752+
ignorePropsValidation = true;
753+
return;
754+
}
755+
756+
let types = buildTypeAnnotationDeclarationTypes(value, key);
757+
if (types === true) {
758+
types = {};
759+
}
760+
types.fullName = key;
761+
types.name = key;
762+
types.node = value;
763+
declaredPropTypes.push(types);
764+
});
765+
}
766+
});
767+
768+
return ignorePropsValidation;
769+
}
770+
727771
/**
728772
* Mark a prop type as declared
729773
* @param {ASTNode} node The AST node being checked.
@@ -791,24 +835,7 @@ module.exports = {
791835
}
792836
break;
793837
case 'IntersectionTypeAnnotation':
794-
propTypes.types.forEach(annotation => {
795-
const propsType = typeScope(annotation.id.name);
796-
iterateProperties(propsType.properties, (key, value) => {
797-
if (!value) {
798-
ignorePropsValidation = true;
799-
return;
800-
}
801-
802-
let types = buildTypeAnnotationDeclarationTypes(value, key);
803-
if (types === true) {
804-
types = {};
805-
}
806-
types.fullName = key;
807-
types.name = key;
808-
types.node = value;
809-
declaredPropTypes.push(types);
810-
});
811-
});
838+
ignorePropsValidation = declarePropTypesForIntersectionTypeAnnotation(propTypes, declaredPropTypes);
812839
break;
813840
case null:
814841
break;

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,38 @@ ruleTester.run('no-unused-prop-types', rule, {
839839
}
840840
`,
841841
parser: 'babel-eslint'
842+
}, {
843+
code: `
844+
type PropsA = { foo: string };
845+
type PropsB = { bar: string };
846+
type PropsC = { zap: string };
847+
type Props = PropsA & PropsB;
848+
849+
class Bar extends React.Component {
850+
props: Props & PropsC;
851+
852+
render() {
853+
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
854+
}
855+
}
856+
`,
857+
parser: 'babel-eslint'
858+
}, {
859+
code: `
860+
import type { PropsA } from "./myPropsA";
861+
type PropsB = { bar: string };
862+
type PropsC = { zap: string };
863+
type Props = PropsA & PropsB;
864+
865+
class Bar extends React.Component {
866+
props: Props & PropsC;
867+
868+
render() {
869+
return <div>{this.props.foo} - {this.props.bar} - {this.props.zap}</div>
870+
}
871+
}
872+
`,
873+
parser: 'babel-eslint'
842874
}, {
843875
code: [
844876
'import type Props from "fake";',
@@ -2743,6 +2775,25 @@ ruleTester.run('no-unused-prop-types', rule, {
27432775
errors: [
27442776
{message: '\'b\' PropType is defined but prop is never used'}
27452777
]
2778+
}, {
2779+
code: `
2780+
type PropsA = { foo: string };
2781+
type PropsB = { bar: string };
2782+
type PropsC = { zap: string };
2783+
type Props = PropsA & PropsB;
2784+
2785+
class Bar extends React.Component {
2786+
props: Props & PropsC;
2787+
2788+
render() {
2789+
return <div>{this.props.foo} - {this.props.bar}</div>
2790+
}
2791+
}
2792+
`,
2793+
parser: 'babel-eslint',
2794+
errors: [
2795+
{message: '\'zap\' PropType is defined but prop is never used'}
2796+
]
27462797
}, {
27472798
code: [
27482799
'class Hello extends React.Component {',

0 commit comments

Comments
 (0)