Skip to content

Commit e75e8dc

Browse files
awearyzpao
authored andcommitted
Warn if PropType function is called manually (facebook#7132)
* Warn if PropType function is called in production * Check if console is undefined before warning * Randomize value of ReactPropTypesSecret * Remove dev environment tests * Rename typeCheckPass to productionWarningCheck * Rename productionWarningCheck to expectWarningInProduction * Call toString on Math.random() * Rename test block for React type checks * Make sure warning isnt emitted for failing props * Cache warning by component and prop, warn in dev * Pass ReactPropTypesSecret to internal checks * Move tests to ReactPropTypes-test.js * Update the warning message to include link * Do not test warning for unions with invalid args (cherry picked from commit 95ac239)
1 parent 4a0a534 commit e75e8dc

File tree

6 files changed

+273
-13
lines changed

6 files changed

+273
-13
lines changed

src/addons/link/__tests__/ReactLinkPropTypes-test.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var emptyFunction = require('emptyFunction');
1515
var LinkPropTypes = require('ReactLink').PropTypes;
1616
var React = require('React');
1717
var ReactPropTypeLocations = require('ReactPropTypeLocations');
18+
var ReactPropTypesSecret = require('ReactPropTypesSecret');
1819

1920
var invalidMessage = 'Invalid prop `testProp` supplied to `testComponent`.';
2021
var requiredMessage =
@@ -26,7 +27,9 @@ function typeCheckFail(declaration, value, message) {
2627
props,
2728
'testProp',
2829
'testComponent',
29-
ReactPropTypeLocations.prop
30+
ReactPropTypeLocations.prop,
31+
null,
32+
ReactPropTypesSecret
3033
);
3134
expect(error instanceof Error).toBe(true);
3235
expect(error.message).toBe(message);
@@ -38,7 +41,9 @@ function typeCheckPass(declaration, value) {
3841
props,
3942
'testProp',
4043
'testComponent',
41-
ReactPropTypeLocations.prop
44+
ReactPropTypeLocations.prop,
45+
null,
46+
ReactPropTypesSecret
4247
);
4348
expect(error).toBe(null);
4449
}

src/isomorphic/classic/types/ReactPropTypes.js

+56-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
var ReactElement = require('ReactElement');
1515
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
16+
var ReactPropTypesSecret = require('ReactPropTypesSecret');
1617

1718
var emptyFunction = require('emptyFunction');
1819
var getIteratorFn = require('getIteratorFn');
@@ -105,16 +106,41 @@ function is(x, y) {
105106
/*eslint-enable no-self-compare*/
106107

107108
function createChainableTypeChecker(validate) {
109+
if (__DEV__) {
110+
var manualPropTypeCallCache = {};
111+
}
108112
function checkType(
109113
isRequired,
110114
props,
111115
propName,
112116
componentName,
113117
location,
114-
propFullName
118+
propFullName,
119+
secret
115120
) {
116121
componentName = componentName || ANONYMOUS;
117122
propFullName = propFullName || propName;
123+
if (__DEV__) {
124+
if (
125+
secret !== ReactPropTypesSecret &&
126+
typeof console !== 'undefined'
127+
) {
128+
var cacheKey = `${componentName}:${propName}`;
129+
if (!manualPropTypeCallCache[cacheKey]) {
130+
warning(
131+
false,
132+
'You are manually calling a React.PropTypes validation ' +
133+
'function for the `%s` prop on `%s`. This is deprecated ' +
134+
'and will not work in the next major version. You may be ' +
135+
'seeing this warning due to a third-party PropTypes library. ' +
136+
'See https://fb.me/react-warning-dont-call-proptypes for details.',
137+
propFullName,
138+
componentName
139+
);
140+
manualPropTypeCallCache[cacheKey] = true;
141+
}
142+
}
143+
}
118144
if (props[propName] == null) {
119145
var locationName = ReactPropTypeLocationNames[location];
120146
if (isRequired) {
@@ -125,7 +151,13 @@ function createChainableTypeChecker(validate) {
125151
}
126152
return null;
127153
} else {
128-
return validate(props, propName, componentName, location, propFullName);
154+
return validate(
155+
props,
156+
propName,
157+
componentName,
158+
location,
159+
propFullName,
160+
);
129161
}
130162
}
131163

@@ -136,7 +168,14 @@ function createChainableTypeChecker(validate) {
136168
}
137169

138170
function createPrimitiveTypeChecker(expectedType) {
139-
function validate(props, propName, componentName, location, propFullName) {
171+
function validate(
172+
props,
173+
propName,
174+
componentName,
175+
location,
176+
propFullName,
177+
secret
178+
) {
140179
var propValue = props[propName];
141180
var propType = getPropType(propValue);
142181
if (propType !== expectedType) {
@@ -183,7 +222,8 @@ function createArrayOfTypeChecker(typeChecker) {
183222
i,
184223
componentName,
185224
location,
186-
`${propFullName}[${i}]`
225+
`${propFullName}[${i}]`,
226+
ReactPropTypesSecret
187227
);
188228
if (error instanceof Error) {
189229
return error;
@@ -272,7 +312,8 @@ function createObjectOfTypeChecker(typeChecker) {
272312
key,
273313
componentName,
274314
location,
275-
`${propFullName}.${key}`
315+
`${propFullName}.${key}`,
316+
ReactPropTypesSecret
276317
);
277318
if (error instanceof Error) {
278319
return error;
@@ -294,7 +335,14 @@ function createUnionTypeChecker(arrayOfTypeCheckers) {
294335
for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
295336
var checker = arrayOfTypeCheckers[i];
296337
if (
297-
checker(props, propName, componentName, location, propFullName) == null
338+
checker(
339+
props,
340+
propName,
341+
componentName,
342+
location,
343+
propFullName,
344+
ReactPropTypesSecret
345+
) == null
298346
) {
299347
return null;
300348
}
@@ -344,7 +392,8 @@ function createShapeTypeChecker(shapeTypes) {
344392
key,
345393
componentName,
346394
location,
347-
`${propFullName}.${key}`
395+
`${propFullName}.${key}`,
396+
ReactPropTypesSecret
348397
);
349398
if (error) {
350399
return error;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule ReactPropTypesSecret
10+
*/
11+
12+
13+
'use strict';
14+
15+
16+
const ReactPropTypesSecret = '__REACT_PROP_TYPES_SECRET__' + Math.random().toString();
17+
18+
module.exports = ReactPropTypesSecret;

0 commit comments

Comments
 (0)