diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js index eab133b350..014a9b3753 100644 --- a/src/isomorphic/classic/types/ReactPropTypes.js +++ b/src/isomorphic/classic/types/ReactPropTypes.js @@ -105,6 +105,20 @@ function is(x, y) { } /*eslint-enable no-self-compare*/ +/** + * We use an Error-like object for backward compatibility as people may call + * PropTypes directly and inspect their output. However we don't use real + * Errors anymore. We don't inspect their stack anyway, and creating them + * is prohibitively expensive if they are created too often, such as what + * happens in oneOfType() for any type before the one that matched. + */ +function PropTypeError(message) { + this.message = message; + this.stack = ''; +} +// Make `instanceof Error` still work for returned errors. +PropTypeError.prototype = Error.prototype; + function createChainableTypeChecker(validate) { if (__DEV__) { var manualPropTypeCallCache = {}; @@ -144,7 +158,7 @@ function createChainableTypeChecker(validate) { if (props[propName] == null) { var locationName = ReactPropTypeLocationNames[location]; if (isRequired) { - return new Error( + return new PropTypeError( `Required ${locationName} \`${propFullName}\` was not specified in ` + `\`${componentName}\`.` ); @@ -185,7 +199,7 @@ function createPrimitiveTypeChecker(expectedType) { // 'of type `object`'. var preciseType = getPreciseType(propValue); - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of type ` + `\`${preciseType}\` supplied to \`${componentName}\`, expected ` + `\`${expectedType}\`.` @@ -203,7 +217,7 @@ function createAnyTypeChecker() { function createArrayOfTypeChecker(typeChecker) { function validate(props, propName, componentName, location, propFullName) { if (typeof typeChecker !== 'function') { - return new Error( + return new PropTypeError( `Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.` ); } @@ -211,7 +225,7 @@ function createArrayOfTypeChecker(typeChecker) { if (!Array.isArray(propValue)) { var locationName = ReactPropTypeLocationNames[location]; var propType = getPropType(propValue); - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of type ` + `\`${propType}\` supplied to \`${componentName}\`, expected an array.` ); @@ -240,7 +254,7 @@ function createElementTypeChecker() { if (!ReactElement.isValidElement(propValue)) { var locationName = ReactPropTypeLocationNames[location]; var propType = getPropType(propValue); - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of type ` + `\`${propType}\` supplied to \`${componentName}\`, expected a single ReactElement.` ); @@ -256,7 +270,7 @@ function createInstanceTypeChecker(expectedClass) { var locationName = ReactPropTypeLocationNames[location]; var expectedClassName = expectedClass.name || ANONYMOUS; var actualClassName = getClassName(props[propName]); - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of type ` + `\`${actualClassName}\` supplied to \`${componentName}\`, expected ` + `instance of \`${expectedClassName}\`.` @@ -283,7 +297,7 @@ function createEnumTypeChecker(expectedValues) { var locationName = ReactPropTypeLocationNames[location]; var valuesString = JSON.stringify(expectedValues); - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of value \`${propValue}\` ` + `supplied to \`${componentName}\`, expected one of ${valuesString}.` ); @@ -294,7 +308,7 @@ function createEnumTypeChecker(expectedValues) { function createObjectOfTypeChecker(typeChecker) { function validate(props, propName, componentName, location, propFullName) { if (typeof typeChecker !== 'function') { - return new Error( + return new PropTypeError( `Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.` ); } @@ -302,7 +316,7 @@ function createObjectOfTypeChecker(typeChecker) { var propType = getPropType(propValue); if (propType !== 'object') { var locationName = ReactPropTypeLocationNames[location]; - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of type ` + `\`${propType}\` supplied to \`${componentName}\`, expected an object.` ); @@ -351,7 +365,7 @@ function createUnionTypeChecker(arrayOfTypeCheckers) { } var locationName = ReactPropTypeLocationNames[location]; - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` supplied to ` + `\`${componentName}\`.` ); @@ -363,7 +377,7 @@ function createNodeChecker() { function validate(props, propName, componentName, location, propFullName) { if (!isNode(props[propName])) { var locationName = ReactPropTypeLocationNames[location]; - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` supplied to ` + `\`${componentName}\`, expected a ReactNode.` ); @@ -379,7 +393,7 @@ function createShapeTypeChecker(shapeTypes) { var propType = getPropType(propValue); if (propType !== 'object') { var locationName = ReactPropTypeLocationNames[location]; - return new Error( + return new PropTypeError( `Invalid ${locationName} \`${propFullName}\` of type \`${propType}\` ` + `supplied to \`${componentName}\`, expected \`object\`.` ); diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js index 6f36dc5420..5183aabe52 100644 --- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js +++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js @@ -195,8 +195,6 @@ describe('ReactPropTypes', function() { expectWarningInDevelopment(PropTypes.object.isRequired, null); expectWarningInDevelopment(PropTypes.object.isRequired, undefined); }); - - }); describe('Any type', function() { @@ -223,7 +221,6 @@ describe('ReactPropTypes', function() { expectWarningInDevelopment(PropTypes.any.isRequired, null); expectWarningInDevelopment(PropTypes.any.isRequired, undefined); }); - }); describe('ArrayOf Type', function() {