Skip to content

Commit 843d71a

Browse files
authored
Merge pull request #1653 from jetpacmonkey/master
Support recursive type annotations, fixes #913
2 parents 7b742d0 + 509f2cb commit 843d71a

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

lib/rules/prop-types.js

+16-5
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,22 @@ module.exports = {
466466
* @return {Object} The representation of the declaration, empty object means
467467
* the property is declared without the need for further analysis.
468468
*/
469-
function buildTypeAnnotationDeclarationTypes(annotation) {
469+
function buildTypeAnnotationDeclarationTypes(annotation, seen) {
470+
if (typeof seen === 'undefined') {
471+
// Keeps track of annotations we've already seen to
472+
// prevent problems with recursive types.
473+
seen = new Set();
474+
}
475+
if (seen.has(annotation)) {
476+
// This must be a recursive type annotation, so just accept anything.
477+
return {};
478+
}
479+
seen.add(annotation);
480+
470481
switch (annotation.type) {
471482
case 'GenericTypeAnnotation':
472483
if (typeScope(annotation.id.name)) {
473-
return buildTypeAnnotationDeclarationTypes(typeScope(annotation.id.name));
484+
return buildTypeAnnotationDeclarationTypes(typeScope(annotation.id.name), seen);
474485
}
475486
return {};
476487
case 'ObjectTypeAnnotation':
@@ -483,7 +494,7 @@ module.exports = {
483494
if (!childKey && !childValue) {
484495
containsObjectTypeSpread = true;
485496
} else {
486-
shapeTypeDefinition.children[childKey] = buildTypeAnnotationDeclarationTypes(childValue);
497+
shapeTypeDefinition.children[childKey] = buildTypeAnnotationDeclarationTypes(childValue, seen);
487498
}
488499
});
489500

@@ -498,7 +509,7 @@ module.exports = {
498509
children: []
499510
};
500511
for (let i = 0, j = annotation.types.length; i < j; i++) {
501-
const type = buildTypeAnnotationDeclarationTypes(annotation.types[i]);
512+
const type = buildTypeAnnotationDeclarationTypes(annotation.types[i], seen);
502513
// keep only complex type
503514
if (Object.keys(type).length > 0) {
504515
if (type.children === true) {
@@ -519,7 +530,7 @@ module.exports = {
519530
return {
520531
type: 'object',
521532
children: {
522-
__ANY_KEY__: buildTypeAnnotationDeclarationTypes(annotation.elementType)
533+
__ANY_KEY__: buildTypeAnnotationDeclarationTypes(annotation.elementType, seen)
523534
}
524535
};
525536
default:

tests/lib/rules/prop-types.js

+14
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,20 @@ ruleTester.run('prop-types', rule, {
15811581
].join('\n'),
15821582
settings: {react: {flowVersion: '0.52'}},
15831583
parser: 'babel-eslint'
1584+
}, {
1585+
code: [
1586+
'type Note = {text: string, children?: Note[]};',
1587+
'type Props = {',
1588+
' notes: Note[];',
1589+
'};',
1590+
'class Hello extends React.Component<void, Props, void> {',
1591+
' render () {',
1592+
' return <div>Hello {this.props.notes[0].text}</div>;',
1593+
' }',
1594+
'}'
1595+
].join('\n'),
1596+
settings: {react: {flowVersion: '0.52'}},
1597+
parser: 'babel-eslint'
15841598
}, {
15851599
code: [
15861600
'import type Props from "fake";',

0 commit comments

Comments
 (0)