Skip to content

Commit b92f2c6

Browse files
author
Joachim Seminck
committed
Add invalid test cases, defer class expressions till program exit
1 parent 8a56b01 commit b92f2c6

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

lib/rules/prop-types.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ module.exports = {
6565
// Used to track the type annotations in scope.
6666
// Necessary because babel's scopes do not track type annotations.
6767
let stack = null;
68+
const classExpressions = [];
6869

6970
const MISSING_MESSAGE = '\'{{name}}\' is missing in props validation';
7071

@@ -872,6 +873,7 @@ module.exports = {
872873
while (annotation && (annotation.type === 'TypeAnnotation' || annotation.type === 'NullableTypeAnnotation')) {
873874
annotation = annotation.typeAnnotation;
874875
}
876+
875877
if (annotation.type === 'GenericTypeAnnotation' && typeScope(annotation.id.name)) {
876878
return typeScope(annotation.id.name);
877879
}
@@ -921,9 +923,10 @@ module.exports = {
921923
},
922924

923925
ClassExpression: function(node) {
924-
if (isSuperTypeParameterPropsDeclaration(node)) {
925-
markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
926-
}
926+
// TypeParameterDeclaration need to be added to typeScope in order to handle ClassExpressions.
927+
// This visitor is executed before TypeParameterDeclaration are scoped, therefore we postpone
928+
// processing class expressions until when the program exists.
929+
classExpressions.push(node);
927930
},
928931

929932
ClassProperty: function(node) {
@@ -1017,6 +1020,14 @@ module.exports = {
10171020
typeScope(node.id.name, node.right);
10181021
},
10191022

1023+
TypeParameterDeclaration: function(node) {
1024+
const identifier = node.params[0];
1025+
1026+
if (identifier.typeAnnotation) {
1027+
typeScope(identifier.name, identifier.typeAnnotation.typeAnnotation);
1028+
}
1029+
},
1030+
10201031
Program: function() {
10211032
stack = [{}];
10221033
},
@@ -1030,6 +1041,12 @@ module.exports = {
10301041
},
10311042

10321043
'Program:exit': function() {
1044+
classExpressions.forEach(node => {
1045+
if (isSuperTypeParameterPropsDeclaration(node)) {
1046+
markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
1047+
}
1048+
});
1049+
10331050
stack = null;
10341051
const list = components.list();
10351052
// Report undeclared proptypes for all classes

tests/lib/rules/prop-types.js

+29
Original file line numberDiff line numberDiff line change
@@ -3295,6 +3295,35 @@ ruleTester.run('prop-types', rule, {
32953295
type: 'Identifier'
32963296
}],
32973297
parser: 'babel-eslint'
3298+
}, {
3299+
code: `
3300+
type Props = { foo: string }
3301+
function higherOrderComponent<Props>() {
3302+
return class extends React.Component<Props> {
3303+
render() {
3304+
return <div>{this.props.foo} - {this.props.bar}</div>
3305+
}
3306+
}
3307+
}
3308+
`,
3309+
errors: [{
3310+
message: '\'bar\' is missing in props validation'
3311+
}],
3312+
parser: 'babel-eslint'
3313+
}, {
3314+
code: `
3315+
function higherOrderComponent<P: { foo: string }>() {
3316+
return class extends React.Component<P> {
3317+
render() {
3318+
return <div>{this.props.foo} - {this.props.bar}</div>
3319+
}
3320+
}
3321+
}
3322+
`,
3323+
errors: [{
3324+
message: '\'bar\' is missing in props validation'
3325+
}],
3326+
parser: 'babel-eslint'
32983327
}
32993328
]
33003329
});

0 commit comments

Comments
 (0)