diff --git a/src/isomorphic/classic/element/ReactElementValidator.js b/src/isomorphic/classic/element/ReactElementValidator.js index 41646c65bd..731d72a708 100644 --- a/src/isomorphic/classic/element/ReactElementValidator.js +++ b/src/isomorphic/classic/element/ReactElementValidator.js @@ -135,6 +135,9 @@ function getAddendaForKeyUse(messageType, element, parentType) { * @param {*} parentType node's parent's type. */ function validateChildKeys(node, parentType) { + if (typeof node !== 'object') { + return; + } if (Array.isArray(node)) { for (var i = 0; i < node.length; i++) { var child = node[i]; diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js index 4bcb4085fc..c528fbb061 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js @@ -449,4 +449,24 @@ describe('ReactElementValidator', function() { expect(console.error.argsForCall.length).toBe(0); }); + it('should not enumerate enumerable numbers (#4776)', function() { + /*eslint-disable no-extend-native */ + Number.prototype['@@iterator'] = function() { + throw new Error('number iterator called'); + }; + /*eslint-enable no-extend-native */ + + try { + void ( +
+ {5} + {12} + {13} +
+ ); + } finally { + delete Number.prototype['@@iterator']; + } + }); + }); diff --git a/src/shared/utils/__tests__/traverseAllChildren-test.js b/src/shared/utils/__tests__/traverseAllChildren-test.js index 013ee52f8d..5c95ec8828 100644 --- a/src/shared/utils/__tests__/traverseAllChildren-test.js +++ b/src/shared/utils/__tests__/traverseAllChildren-test.js @@ -435,4 +435,45 @@ describe('traverseAllChildren', function() { ); }); + it('should not enumerate enumerable numbers (#4776)', function() { + /*eslint-disable no-extend-native */ + Number.prototype['@@iterator'] = function() { + throw new Error('number iterator called'); + }; + /*eslint-enable no-extend-native */ + + try { + var instance = ( +
+ {5} + {12} + {13} +
+ ); + + var traverseFn = jasmine.createSpy(); + + traverseAllChildren(instance.props.children, traverseFn, null); + expect(traverseFn.calls.length).toBe(3); + + expect(traverseFn).toHaveBeenCalledWith( + null, + 5, + '.0' + ); + expect(traverseFn).toHaveBeenCalledWith( + null, + 12, + '.1' + ); + expect(traverseFn).toHaveBeenCalledWith( + null, + 13, + '.2' + ); + } finally { + delete Number.prototype['@@iterator']; + } + }); + });