From 6893763897557459c3d9d304536b04acd41d4cc9 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Thu, 28 May 2015 12:06:02 -0700 Subject: [PATCH] add an intersection version of PropType.oneOfType called PropType.allOfType --- .../classic/types/ReactPropTypes.js | 23 ++++++ .../types/__tests__/ReactPropTypes-test.js | 76 +++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index c8425f666ab66..993700dee2c08 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -81,6 +81,7 @@ var ReactPropTypes = { node: createNodeChecker(), objectOf: createObjectOfTypeChecker, oneOf: createEnumTypeChecker, + allOfType: createIntersectionTypeChecker, oneOfType: createUnionTypeChecker, shape: createShapeTypeChecker }; @@ -256,6 +257,28 @@ function createObjectOfTypeChecker(typeChecker) { return createChainableTypeChecker(validate); } +function createIntersectionTypeChecker(arrayOfTypeCheckers) { + if (!Array.isArray(arrayOfTypeCheckers)) { + return createChainableTypeChecker(function() { + return new Error( + `Invalid argument supplied to allOfType, expected an instance of array.` + ); + }); + } + + function validate(props, propName, componentName, location, propFullName) { + for (var i = 0; i < arrayOfTypeCheckers.length; i++) { + var checker = arrayOfTypeCheckers[i]; + var error = checker(props, propName, componentName, location, propFullName); + if (error instanceof Error) { + return error; + } + } + return null; + } + return createChainableTypeChecker(validate); +} + function createUnionTypeChecker(arrayOfTypeCheckers) { if (!Array.isArray(arrayOfTypeCheckers)) { return createChainableTypeChecker(function() { diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 0992f4f6eb7be..8fc964a3cc6a2 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -579,6 +579,82 @@ describe('ReactPropTypes', function() { }); }); + describe('Intersection Types', function() { + it("should fail for invalid argument", function() { + typeCheckFail( + PropTypes.allOfType(PropTypes.string, PropTypes.number), + 'red', + 'Invalid argument supplied to allOfType, expected an instance of array.' + ); + }); + + it('should warn if none of the types are valid', function() { + typeCheckFail( + PropTypes.allOfType([PropTypes.string, PropTypes.number]), + [], + 'Invalid prop `testProp` of type `array` supplied to `testComponent`, expected `string`.' + ); + + typeCheckFail( + PropTypes.allOfType([PropTypes.number, PropTypes.string]), + [], + 'Invalid prop `testProp` of type `array` supplied to `testComponent`, expected `number`.' + ); + + var checker = PropTypes.allOfType([ + PropTypes.shape({a: PropTypes.number.isRequired}), + PropTypes.shape({b: PropTypes.number.isRequired}) + ]); + typeCheckFail( + checker, + {a: 1}, + 'Required prop `testProp.b` was not specified in `testComponent`.' + ); + typeCheckFail( + checker, + {b: 1}, + 'Required prop `testProp.a` was not specified in `testComponent`.' + ); + }); + + it('should not warn if all of the types are valid', function() { + var checker = PropTypes.allOfType([ + PropTypes.number, + PropTypes.number + ]); + typeCheckPass(checker, null); + typeCheckPass(checker, 123); + + checker = PropTypes.allOfType([ + PropTypes.shape({a: PropTypes.number.isRequired}), + PropTypes.shape({b: PropTypes.number.isRequired}) + ]); + typeCheckPass(checker, {a: 1, b: 1}); + }); + + it("should be implicitly optional and not warn without values", function() { + typeCheckPass( + PropTypes.allOfType([PropTypes.string, PropTypes.string]), null + ); + typeCheckPass( + PropTypes.allOfType([PropTypes.string, PropTypes.string]), undefined + ); + }); + + it("should warn for missing required values", function() { + typeCheckFail( + PropTypes.allOfType([PropTypes.string, PropTypes.string]).isRequired, + null, + requiredMessage + ); + typeCheckFail( + PropTypes.allOfType([PropTypes.string, PropTypes.string]).isRequired, + undefined, + requiredMessage + ); + }); + }); + describe('Union Types', function() { it("should fail for invalid argument", function() { typeCheckFail(