diff --git a/packages/react/src/ReactElementValidator.js b/packages/react/src/ReactElementValidator.js
index f3f16f7649576..8fb5d2e6c5ddd 100644
--- a/packages/react/src/ReactElementValidator.js
+++ b/packages/react/src/ReactElementValidator.js
@@ -26,6 +26,8 @@ import ReactDebugCurrentFrame from './ReactDebugCurrentFrame';
if (__DEV__) {
var currentlyValidatingElement = null;
+ var propTypesMisspellWarningShown = false;
+
var getDisplayName = function(element): string {
if (element == null) {
return '#empty';
@@ -212,11 +214,20 @@ function validatePropTypes(element) {
}
var name = componentClass.displayName || componentClass.name;
var propTypes = componentClass.propTypes;
-
if (propTypes) {
currentlyValidatingElement = element;
checkPropTypes(propTypes, element.props, 'prop', name, getStackAddendum);
currentlyValidatingElement = null;
+ } else if (
+ componentClass.PropTypes !== undefined &&
+ !propTypesMisspellWarningShown
+ ) {
+ propTypesMisspellWarningShown = true;
+ warning(
+ false,
+ 'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
+ name || 'Unknown',
+ );
}
if (typeof componentClass.getDefaultProps === 'function') {
warning(
diff --git a/packages/react/src/__tests__/ReactElementValidator-test.js b/packages/react/src/__tests__/ReactElementValidator-test.js
index 5f0f348b995da..c18dea2c1a762 100644
--- a/packages/react/src/__tests__/ReactElementValidator-test.js
+++ b/packages/react/src/__tests__/ReactElementValidator-test.js
@@ -448,6 +448,29 @@ describe('ReactElementValidator', () => {
}
});
+ it('should warn if component declares PropTypes instead of propTypes', () => {
+ spyOn(console, 'error');
+ class MisspelledPropTypesComponent extends React.Component {
+ static PropTypes = {
+ prop: PropTypes.string,
+ };
+ render() {
+ return React.createElement('span', null, this.props.prop);
+ }
+ }
+
+ ReactTestUtils.renderIntoDocument(
+ React.createElement(MisspelledPropTypesComponent, {prop: 'Hi'}),
+ );
+ if (__DEV__) {
+ expect(console.error.calls.count()).toBe(1);
+ expect(console.error.calls.argsFor(0)[0]).toBe(
+ 'Warning: Component MisspelledPropTypesComponent declared `PropTypes` ' +
+ 'instead of `propTypes`. Did you misspell the property assignment?',
+ );
+ }
+ });
+
it('should warn when accessing .type on an element factory', () => {
spyOnDev(console, 'warn');
function TestComponent() {
diff --git a/packages/react/src/__tests__/ReactJSXElementValidator-test.js b/packages/react/src/__tests__/ReactJSXElementValidator-test.js
index d935fd707598b..82c2a60c4045d 100644
--- a/packages/react/src/__tests__/ReactJSXElementValidator-test.js
+++ b/packages/react/src/__tests__/ReactJSXElementValidator-test.js
@@ -484,4 +484,26 @@ describe('ReactJSXElementValidator', () => {
);
}
});
+
+ it('should warn if component declares PropTypes instead of propTypes', () => {
+ spyOn(console, 'error');
+ class MisspelledPropTypesComponent extends React.Component {
+ render() {
+ return {this.props.prop};
+ }
+ }
+ MisspelledPropTypesComponent.PropTypes = {
+ prop: PropTypes.string,
+ };
+ ReactTestUtils.renderIntoDocument(
+ ,
+ );
+ if (__DEV__) {
+ expect(console.error.calls.count()).toBe(1);
+ expect(console.error.calls.argsFor(0)[0]).toBe(
+ 'Warning: Component MisspelledPropTypesComponent declared `PropTypes` ' +
+ 'instead of `propTypes`. Did you misspell the property assignment?',
+ );
+ }
+ });
});