diff --git a/lib/rules/prop-types.js b/lib/rules/prop-types.js index a17d7cd0e9..7466c3a2f1 100644 --- a/lib/rules/prop-types.js +++ b/lib/rules/prop-types.js @@ -466,11 +466,22 @@ module.exports = { * @return {Object} The representation of the declaration, empty object means * the property is declared without the need for further analysis. */ - function buildTypeAnnotationDeclarationTypes(annotation) { + function buildTypeAnnotationDeclarationTypes(annotation, seen) { + if (typeof seen === 'undefined') { + // Keeps track of annotations we've already seen to + // prevent problems with recursive types. + seen = new Set(); + } + if (seen.has(annotation)) { + // This must be a recursive type annotation, so just accept anything. + return {}; + } + seen.add(annotation); + switch (annotation.type) { case 'GenericTypeAnnotation': if (typeScope(annotation.id.name)) { - return buildTypeAnnotationDeclarationTypes(typeScope(annotation.id.name)); + return buildTypeAnnotationDeclarationTypes(typeScope(annotation.id.name), seen); } return {}; case 'ObjectTypeAnnotation': @@ -483,7 +494,7 @@ module.exports = { if (!childKey && !childValue) { containsObjectTypeSpread = true; } else { - shapeTypeDefinition.children[childKey] = buildTypeAnnotationDeclarationTypes(childValue); + shapeTypeDefinition.children[childKey] = buildTypeAnnotationDeclarationTypes(childValue, seen); } }); @@ -498,7 +509,7 @@ module.exports = { children: [] }; for (let i = 0, j = annotation.types.length; i < j; i++) { - const type = buildTypeAnnotationDeclarationTypes(annotation.types[i]); + const type = buildTypeAnnotationDeclarationTypes(annotation.types[i], seen); // keep only complex type if (Object.keys(type).length > 0) { if (type.children === true) { @@ -519,7 +530,7 @@ module.exports = { return { type: 'object', children: { - __ANY_KEY__: buildTypeAnnotationDeclarationTypes(annotation.elementType) + __ANY_KEY__: buildTypeAnnotationDeclarationTypes(annotation.elementType, seen) } }; default: diff --git a/tests/lib/rules/prop-types.js b/tests/lib/rules/prop-types.js index 3ee4072ac3..de25474b76 100644 --- a/tests/lib/rules/prop-types.js +++ b/tests/lib/rules/prop-types.js @@ -1581,6 +1581,20 @@ ruleTester.run('prop-types', rule, { ].join('\n'), settings: {react: {flowVersion: '0.52'}}, parser: 'babel-eslint' + }, { + code: [ + 'type Note = {text: string, children?: Note[]};', + 'type Props = {', + ' notes: Note[];', + '};', + 'class Hello extends React.Component {', + ' render () {', + ' return
Hello {this.props.notes[0].text}
;', + ' }', + '}' + ].join('\n'), + settings: {react: {flowVersion: '0.52'}}, + parser: 'babel-eslint' }, { code: [ 'import type Props from "fake";',