diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js
index 87a8de23b3f..69486ca1e37 100644
--- a/src/core/ReactCompositeComponent.js
+++ b/src/core/ReactCompositeComponent.js
@@ -987,7 +987,19 @@ var ReactCompositeComponentMixin = {
// TODO: Stop validating prop types here and only use the descriptor
// validation.
var componentName = this.constructor.displayName;
- for (var propName in propTypes) {
+ var propName;
+
+ for (propName in props) {
+ if (props.hasOwnProperty(propName) &&
+ !propTypes.hasOwnProperty(propName)) {
+ var message = location.substring(0,1).toUpperCase() +
+ location.substring(1) + " `" + propName +
+ "` was not expected in " + ("`" + componentName + "`.");
+ warning(false, message);
+ }
+ }
+
+ for (propName in propTypes) {
if (propTypes.hasOwnProperty(propName)) {
var error =
propTypes[propName](props, propName, componentName, location);
diff --git a/src/core/ReactDescriptorValidator.js b/src/core/ReactDescriptorValidator.js
index 4123160d170..1b2dce86017 100644
--- a/src/core/ReactDescriptorValidator.js
+++ b/src/core/ReactDescriptorValidator.js
@@ -199,7 +199,22 @@ function validateChildKeys(component, parentType) {
* @private
*/
function checkPropTypes(componentName, propTypes, props, location) {
- for (var propName in propTypes) {
+ var propName;
+ for (propName in props) {
+ if (props.hasOwnProperty(propName) &&
+ !propTypes.hasOwnProperty(propName)) {
+ var message = location.substring(0,1).toUpperCase() +
+ location.substring(1) + " `" + propName +
+ "` was not expected in " + ("`" + componentName + "`.");
+ loggedTypeFailures[message] = true;
+ monitorCodeUse(
+ 'react_failed_descriptor_type_check',
+ { message: message }
+ );
+ }
+ }
+
+ for (propName in propTypes) {
if (propTypes.hasOwnProperty(propName)) {
var error;
// Prop type validation may throw. In case they do, we don't want to
diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js
index a970b171693..e3f1b77197c 100644
--- a/src/core/__tests__/ReactCompositeComponent-test.js
+++ b/src/core/__tests__/ReactCompositeComponent-test.js
@@ -553,6 +553,22 @@ describe('ReactCompositeComponent', function() {
expect(console.warn.mock.calls.length).toBe(2);
});
+ it('should warn about unexpected props', function() {
+ var Component = React.createClass({
+ propTypes: {},
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.mock.calls.length).toBe(1);
+ expect(console.warn.mock.calls[0][0]).toBe(
+ 'Warning: Prop `prop` was not expected in `Component`.'
+ );
+ });
+
it('should throw on invalid prop types', function() {
expect(function() {
React.createClass({