Skip to content

Commit 500d4c3

Browse files
committed
Merge pull request #4209 from aruberto/iterable_node_proptype
Allow iterables to pass node prop type check
2 parents a8955e7 + 79fc73e commit 500d4c3

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

src/isomorphic/classic/types/ReactPropTypes.js

+30-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var ReactFragment = require('ReactFragment');
1616
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
1717

1818
var emptyFunction = require('emptyFunction');
19+
var getIteratorFn = require('getIteratorFn');
1920

2021
/**
2122
* Collection of methods that allow declaration and validation of props that are
@@ -345,12 +346,37 @@ function isNode(propValue) {
345346
if (propValue === null || ReactElement.isValidElement(propValue)) {
346347
return true;
347348
}
348-
propValue = ReactFragment.extractIfFragment(propValue);
349-
for (var k in propValue) {
350-
if (!isNode(propValue[k])) {
351-
return false;
349+
350+
var iteratorFn = getIteratorFn(propValue);
351+
if (iteratorFn) {
352+
var iterator = iteratorFn.call(propValue);
353+
var step;
354+
if (iteratorFn !== propValue.entries) {
355+
while (!(step = iterator.next()).done) {
356+
if (!isNode(step.value)) {
357+
return false;
358+
}
359+
}
360+
} else {
361+
// Iterator will provide entry [k,v] tuples rather than values.
362+
while (!(step = iterator.next()).done) {
363+
var entry = step.value;
364+
if (entry) {
365+
if (!isNode(entry[1])) {
366+
return false;
367+
}
368+
}
369+
}
370+
}
371+
} else {
372+
propValue = ReactFragment.extractIfFragment(propValue);
373+
for (var k in propValue) {
374+
if (!isNode(propValue[k])) {
375+
return false;
376+
}
352377
}
353378
}
379+
354380
return true;
355381
default:
356382
return false;

src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js

+33
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,39 @@ describe('ReactPropTypes', function() {
405405
});
406406
});
407407

408+
it('should not warn for iterables', function() {
409+
var iterable = {
410+
'@@iterator': function() {
411+
var i = 0;
412+
return {
413+
next: function() {
414+
var done = ++i > 2;
415+
return {value: done ? undefined : <MyComponent />, done: done};
416+
},
417+
};
418+
},
419+
};
420+
421+
typeCheckPass(PropTypes.node, iterable);
422+
});
423+
424+
it('should not warn for entry iterables', function() {
425+
var iterable = {
426+
'@@iterator': function() {
427+
var i = 0;
428+
return {
429+
next: function() {
430+
var done = ++i > 2;
431+
return {value: done ? undefined : ['#' + i, <MyComponent />], done: done};
432+
},
433+
};
434+
},
435+
};
436+
iterable.entries = iterable['@@iterator'];
437+
438+
typeCheckPass(PropTypes.node, iterable);
439+
});
440+
408441
it('should not warn for null/undefined if not required', function() {
409442
typeCheckPass(PropTypes.node, null);
410443
typeCheckPass(PropTypes.node, undefined);

0 commit comments

Comments
 (0)