diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js
index 5382931bb47b0..250531f2e7873 100644
--- a/src/isomorphic/classic/types/ReactPropTypes.js
+++ b/src/isomorphic/classic/types/ReactPropTypes.js
@@ -16,6 +16,7 @@ var ReactFragment = require('ReactFragment');
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
var emptyFunction = require('emptyFunction');
+var getIteratorFn = require('getIteratorFn');
/**
* Collection of methods that allow declaration and validation of props that are
@@ -345,12 +346,37 @@ function isNode(propValue) {
if (propValue === null || ReactElement.isValidElement(propValue)) {
return true;
}
- propValue = ReactFragment.extractIfFragment(propValue);
- for (var k in propValue) {
- if (!isNode(propValue[k])) {
- return false;
+
+ var iteratorFn = getIteratorFn(propValue);
+ if (iteratorFn) {
+ var iterator = iteratorFn.call(propValue);
+ var step;
+ if (iteratorFn !== propValue.entries) {
+ while (!(step = iterator.next()).done) {
+ if (!isNode(step.value)) {
+ return false;
+ }
+ }
+ } else {
+ // Iterator will provide entry [k,v] tuples rather than values.
+ while (!(step = iterator.next()).done) {
+ var entry = step.value;
+ if (entry) {
+ if (!isNode(entry[1])) {
+ return false;
+ }
+ }
+ }
+ }
+ } else {
+ propValue = ReactFragment.extractIfFragment(propValue);
+ for (var k in propValue) {
+ if (!isNode(propValue[k])) {
+ return false;
+ }
}
}
+
return true;
default:
return false;
diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
index 7c37fa59607f4..412d0f2e695c9 100644
--- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
+++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
@@ -405,6 +405,39 @@ describe('ReactPropTypes', function() {
});
});
+ it('should not warn for iterables', function() {
+ var iterable = {
+ '@@iterator': function() {
+ var i = 0;
+ return {
+ next: function() {
+ var done = ++i > 2;
+ return {value: done ? undefined : , done: done};
+ },
+ };
+ },
+ };
+
+ typeCheckPass(PropTypes.node, iterable);
+ });
+
+ it('should not warn for entry iterables', function() {
+ var iterable = {
+ '@@iterator': function() {
+ var i = 0;
+ return {
+ next: function() {
+ var done = ++i > 2;
+ return {value: done ? undefined : ['#' + i, ], done: done};
+ },
+ };
+ },
+ };
+ iterable.entries = iterable['@@iterator'];
+
+ typeCheckPass(PropTypes.node, iterable);
+ });
+
it('should not warn for null/undefined if not required', function() {
typeCheckPass(PropTypes.node, null);
typeCheckPass(PropTypes.node, undefined);