Merge pull request #1611 from mathieumg/master

Added 'objectOf' PropType validator to iterate on objects and validate properties.
This commit is contained in:
Cheng Lou 2014-06-12 20:19:33 -07:00
commit 4329d5ac38
2 changed files with 121 additions and 2 deletions

View File

@ -83,6 +83,7 @@ var ReactPropTypes = {
arrayOf: createArrayOfTypeChecker,
component: createComponentTypeChecker(),
instanceOf: createInstanceTypeChecker,
objectOf: createObjectOfTypeChecker,
oneOf: createEnumTypeChecker,
oneOfType: createUnionTypeChecker,
renderable: createRenderableTypeChecker(),
@ -202,6 +203,29 @@ function createEnumTypeChecker(expectedValues) {
return createChainableTypeChecker(validate);
}
function createObjectOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
var locationName = ReactPropTypeLocationNames[location];
return new Error(
`Invalid ${locationName} \`${propName}\` of type ` +
`\`${propType}\` supplied to \`${componentName}\`, expected an object.`
);
}
for (var key in propValue) {
if (propValue.hasOwnProperty(key)) {
var error = typeChecker(propValue, key, componentName, location);
if (error instanceof Error) {
return error;
}
}
}
}
return createChainableTypeChecker(validate);
}
function createUnionTypeChecker(arrayOfTypeCheckers) {
function validate(props, propName, componentName, location) {
for (var i = 0; i < arrayOfTypeCheckers.length; i++) {

View File

@ -406,6 +406,97 @@ describe('React Component Types', function() {
});
});
describe('ObjectOf Type', function() {
it('should support the objectOf propTypes', function() {
typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
typeCheckPass(
PropTypes.objectOf(PropTypes.string),
{a: 'a', b: 'b', c: 'c'}
);
typeCheckPass(
PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
{a: 'a', b: 'b'}
);
});
it('should support objectOf with complex types', function() {
typeCheckPass(
PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
{a: {a: 1}, b: {a: 2}}
);
function Thing() {}
typeCheckPass(
PropTypes.objectOf(PropTypes.instanceOf(Thing)),
{a: new Thing(), b: new Thing()}
);
});
it('should warn with invalid items in the object', function() {
typeCheckFail(
PropTypes.objectOf(PropTypes.number),
{a: 1, b: 2, c: 'b'},
'Invalid prop `c` of type `string` supplied to `testComponent`, ' +
'expected `number`.'
);
});
it('should warn with invalid complex types', function() {
function Thing() {}
var name = Thing.name || '<<anonymous>>';
typeCheckFail(
PropTypes.objectOf(PropTypes.instanceOf(Thing)),
{a: new Thing(), b: 'xyz'},
'Invalid prop `b` supplied to `testComponent`, expected instance of `' +
name + '`.'
);
});
it('should warn when passed something other than an object', function() {
typeCheckFail(
PropTypes.objectOf(PropTypes.number),
[1, 2],
'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
'expected an object.'
);
typeCheckFail(
PropTypes.objectOf(PropTypes.number),
123,
'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
'expected an object.'
);
typeCheckFail(
PropTypes.objectOf(PropTypes.number),
'string',
'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
'expected an object.'
);
});
it('should not warn when passing an empty object', function() {
typeCheckPass(PropTypes.objectOf(PropTypes.number), {});
});
it("should be implicitly optional and not warn without values", function() {
typeCheckPass(PropTypes.objectOf(PropTypes.number), null);
typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined);
});
it("should warn for missing required values", function() {
typeCheckFail(
PropTypes.objectOf(PropTypes.number).isRequired,
null,
requiredMessage
);
typeCheckFail(
PropTypes.objectOf(PropTypes.number).isRequired,
undefined,
requiredMessage
);
});
});
describe('OneOf Types', function() {
it("should warn for invalid strings", function() {
typeCheckFail(
@ -446,10 +537,14 @@ describe('OneOf Types', function() {
it("should warn for missing required values", function() {
typeCheckFail(
PropTypes.oneOf(['red', 'blue']).isRequired, null, requiredMessage
PropTypes.oneOf(['red', 'blue']).isRequired,
null,
requiredMessage
);
typeCheckFail(
PropTypes.oneOf(['red', 'blue']).isRequired, undefined, requiredMessage
PropTypes.oneOf(['red', 'blue']).isRequired,
undefined,
requiredMessage
);
});
});