mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Add PropTypes.checkPropTypes API
Allows users to check arbitrary objects against React prop types without relying on the implementation details of the prop validators themselves. An example of why this is important: some prop validators may throw, while others return an error object. Calling a prop validator manually requires handling both cases. `checkPropTypes` does this for you.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
var ReactElement = require('ReactElement');
|
||||
var ReactPropTypesSecret = require('ReactPropTypesSecret');
|
||||
var checkReactTypeSpec = require('checkReactTypeSpec');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var getIteratorFn = require('getIteratorFn');
|
||||
@@ -122,6 +123,12 @@ if (__DEV__) {
|
||||
};
|
||||
}
|
||||
|
||||
function checkPropTypes(propTypes, object, location, componentName, warnOnRepeat) {
|
||||
checkReactTypeSpec(propTypes, object, location, componentName, null, null, warnOnRepeat);
|
||||
}
|
||||
ReactPropTypes.checkPropTypes = checkPropTypes;
|
||||
|
||||
|
||||
/**
|
||||
* inlined Object.is polyfill to avoid requiring consumers ship their own
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
||||
|
||||
@@ -15,23 +15,36 @@ var PropTypes;
|
||||
var React;
|
||||
var ReactFragment;
|
||||
var ReactTestUtils;
|
||||
var ReactPropTypesSecret;
|
||||
|
||||
var Component;
|
||||
var MyComponent;
|
||||
|
||||
function typeCheckFail(declaration, value, message) {
|
||||
var props = {testProp: value};
|
||||
var error = declaration(
|
||||
props,
|
||||
'testProp',
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
expect(error instanceof Error).toBe(true);
|
||||
expect(error.message).toBe(message);
|
||||
function getPropTypeWarningMessage(propTypes, object, componentName) {
|
||||
if (!console.error.calls) {
|
||||
spyOn(console, 'error');
|
||||
} else {
|
||||
console.error.calls.reset();
|
||||
}
|
||||
PropTypes.checkPropTypes(propTypes, object, 'prop', 'testComponent', true);
|
||||
const callCount = console.error.calls.count();
|
||||
if (callCount > 1) {
|
||||
throw new Error('Too many warnings.');
|
||||
}
|
||||
const message = console.error.calls.argsFor(0)[0] || null;
|
||||
console.error.calls.reset();
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function typeCheckFail(declaration, value, expectedMessage) {
|
||||
const propTypes = {
|
||||
testProp: declaration,
|
||||
};
|
||||
const props = {
|
||||
testProp: value,
|
||||
};
|
||||
const message = getPropTypeWarningMessage(propTypes, props, 'testComponent');
|
||||
expect(message).toContain(expectedMessage);
|
||||
}
|
||||
|
||||
function typeCheckFailRequiredValues(declaration) {
|
||||
@@ -39,52 +52,31 @@ function typeCheckFailRequiredValues(declaration) {
|
||||
'`testComponent`, but its value is `null`.';
|
||||
var unspecifiedMsg = 'The prop `testProp` is marked as required in ' +
|
||||
'`testComponent`, but its value is \`undefined\`.';
|
||||
var props1 = {testProp: null};
|
||||
var error1 = declaration(
|
||||
props1,
|
||||
'testProp',
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
expect(error1 instanceof Error).toBe(true);
|
||||
expect(error1.message).toBe(specifiedButIsNullMsg);
|
||||
var props2 = {testProp: undefined};
|
||||
var error2 = declaration(
|
||||
props2,
|
||||
'testProp',
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
expect(error2 instanceof Error).toBe(true);
|
||||
expect(error2.message).toBe(unspecifiedMsg);
|
||||
var props3 = {};
|
||||
var error3 = declaration(
|
||||
props3,
|
||||
'testProp',
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
expect(error3 instanceof Error).toBe(true);
|
||||
expect(error3.message).toBe(unspecifiedMsg);
|
||||
|
||||
var propTypes = { testProp: declaration };
|
||||
|
||||
// Required prop is null
|
||||
var message1 = getPropTypeWarningMessage(propTypes, { testProp: null }, 'testComponent');
|
||||
expect(message1).toContain(specifiedButIsNullMsg);
|
||||
|
||||
// Required prop is undefined
|
||||
var message2 = getPropTypeWarningMessage(propTypes, { testProp: undefined }, 'testComponent');
|
||||
expect(message2).toContain(unspecifiedMsg);
|
||||
|
||||
// Required prop is not a member of props object
|
||||
var message3 = getPropTypeWarningMessage(propTypes, {}, 'testComponent');
|
||||
expect(message3).toContain(unspecifiedMsg);
|
||||
}
|
||||
|
||||
function typeCheckPass(declaration, value) {
|
||||
var props = {testProp: value};
|
||||
var error = declaration(
|
||||
props,
|
||||
'testProp',
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
expect(error).toBe(null);
|
||||
const propTypes = {
|
||||
testProp: declaration,
|
||||
};
|
||||
const props = {
|
||||
testProp: value,
|
||||
};
|
||||
const message = getPropTypeWarningMessage(propTypes, props, 'testComponent');
|
||||
expect(message).toBe(null);
|
||||
}
|
||||
|
||||
function expectWarningInDevelopment(declaration, value) {
|
||||
@@ -112,7 +104,6 @@ describe('ReactPropTypes', () => {
|
||||
React = require('React');
|
||||
ReactFragment = require('ReactFragment');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
ReactPropTypesSecret = require('ReactPropTypesSecret');
|
||||
});
|
||||
|
||||
describe('Primitive Types', () => {
|
||||
|
||||
@@ -54,6 +54,8 @@ function checkReactTypeSpec(
|
||||
// It is only safe to pass fiber if it is the work-in-progress version, and
|
||||
// only during reconciliation (begin and complete phase).
|
||||
workInProgressOrDebugID,
|
||||
// Default behavior is to suppress repeated warnings, but can be overridden
|
||||
warnOnRepeat
|
||||
) {
|
||||
for (var typeSpecName in typeSpecs) {
|
||||
if (typeSpecs.hasOwnProperty(typeSpecName)) {
|
||||
@@ -88,7 +90,7 @@ function checkReactTypeSpec(
|
||||
typeSpecName,
|
||||
typeof error
|
||||
);
|
||||
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
|
||||
if (error instanceof Error && (warnOnRepeat || !(error.message in loggedTypeFailures))) {
|
||||
// Only monitor this failure once because there tends to be a lot of the
|
||||
// same error.
|
||||
loggedTypeFailures[error.message] = true;
|
||||
|
||||
Reference in New Issue
Block a user