mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
Remove JSX propTypes validation (#28328)
This removes the remaining `propTypes` validation calls, making
declaring `propTypes` a no-op. In other words, React itself will no
longer validate the `propTypes` that you declare on your components.
In general, our recommendation is to use static type checking (e.g.
TypeScript). If you'd like to still run propTypes checks, you can do so
manually, same as you'd do outside React:
```js
import checkPropTypes from 'prop-types/checkPropTypes';
function Button(props) {
checkPropTypes(Button.propTypes, prop, 'prop', Button.name)
// ...
}
```
This could be automated as a Babel plugin if you want to keep these
checks implicit. (We will not be providing such a plugin, but someone in
community might be interested in building or maintaining one.)
This commit is contained in:
parent
4ea424e63d
commit
353ecd0516
5
packages/react-art/npm/Circle.js
vendored
5
packages/react-art/npm/Circle.js
vendored
|
|
@ -18,7 +18,6 @@
|
|||
'use strict';
|
||||
|
||||
var assign = Object.assign;
|
||||
var PropTypes = require('prop-types');
|
||||
var React = require('react');
|
||||
var ReactART = require('react-art');
|
||||
|
||||
|
|
@ -34,10 +33,6 @@ var Shape = ReactART.Shape;
|
|||
var Circle = createReactClass({
|
||||
displayName: 'Circle',
|
||||
|
||||
propTypes: {
|
||||
radius: PropTypes.number.isRequired,
|
||||
},
|
||||
|
||||
render: function render() {
|
||||
var radius = this.props.radius;
|
||||
|
||||
|
|
|
|||
11
packages/react-art/npm/Rectangle.js
vendored
11
packages/react-art/npm/Rectangle.js
vendored
|
|
@ -25,7 +25,6 @@
|
|||
'use strict';
|
||||
|
||||
var assign = Object.assign;
|
||||
var PropTypes = require('prop-types');
|
||||
var React = require('react');
|
||||
var ReactART = require('react-art');
|
||||
|
||||
|
|
@ -41,16 +40,6 @@ var Path = ReactART.Path;
|
|||
var Rectangle = createReactClass({
|
||||
displayName: 'Rectangle',
|
||||
|
||||
propTypes: {
|
||||
width: PropTypes.number.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
radius: PropTypes.number,
|
||||
radiusTopLeft: PropTypes.number,
|
||||
radiusTopRight: PropTypes.number,
|
||||
radiusBottomRight: PropTypes.number,
|
||||
radiusBottomLeft: PropTypes.number,
|
||||
},
|
||||
|
||||
render: function render() {
|
||||
var width = this.props.width;
|
||||
var height = this.props.height;
|
||||
|
|
|
|||
8
packages/react-art/npm/Wedge.js
vendored
8
packages/react-art/npm/Wedge.js
vendored
|
|
@ -21,7 +21,6 @@
|
|||
'use strict';
|
||||
|
||||
var assign = Object.assign;
|
||||
var PropTypes = require('prop-types');
|
||||
var React = require('react');
|
||||
var ReactART = require('react-art');
|
||||
|
||||
|
|
@ -37,13 +36,6 @@ var Path = ReactART.Path;
|
|||
var Wedge = createReactClass({
|
||||
displayName: 'Wedge',
|
||||
|
||||
propTypes: {
|
||||
outerRadius: PropTypes.number.isRequired,
|
||||
startAngle: PropTypes.number.isRequired,
|
||||
endAngle: PropTypes.number.isRequired,
|
||||
innerRadius: PropTypes.number,
|
||||
},
|
||||
|
||||
circleRadians: Math.PI * 2,
|
||||
|
||||
radiansPerDegree: Math.PI / 180,
|
||||
|
|
|
|||
|
|
@ -456,18 +456,6 @@ describe('ReactARTComponents', () => {
|
|||
expect(circle.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should warn if radius is missing on a Circle component', () => {
|
||||
expect(() =>
|
||||
ReactTestRenderer.create(
|
||||
<Circle stroke="green" strokeWidth={3} fill="blue" />,
|
||||
),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: The prop `radius` is marked as required in `Circle`, ' +
|
||||
'but its value is `undefined`.' +
|
||||
'\n in Circle (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should generate a <Shape> with props for drawing the Rectangle', () => {
|
||||
const rectangle = ReactTestRenderer.create(
|
||||
<Rectangle width={50} height={50} stroke="green" fill="blue" />,
|
||||
|
|
@ -529,19 +517,6 @@ describe('ReactARTComponents', () => {
|
|||
expect(rectangle.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should warn if width/height is missing on a Rectangle component', () => {
|
||||
expect(() =>
|
||||
ReactTestRenderer.create(<Rectangle stroke="green" fill="blue" />),
|
||||
).toErrorDev([
|
||||
'Warning: Failed prop type: The prop `width` is marked as required in `Rectangle`, ' +
|
||||
'but its value is `undefined`.' +
|
||||
'\n in Rectangle (at **)',
|
||||
'Warning: Failed prop type: The prop `height` is marked as required in `Rectangle`, ' +
|
||||
'but its value is `undefined`.' +
|
||||
'\n in Rectangle (at **)',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate a <Shape> with props for drawing the Wedge', () => {
|
||||
const wedge = ReactTestRenderer.create(
|
||||
<Wedge outerRadius={50} startAngle={0} endAngle={360} fill="blue" />,
|
||||
|
|
@ -555,18 +530,4 @@ describe('ReactARTComponents', () => {
|
|||
);
|
||||
expect(wedge.toJSON()).toBeNull();
|
||||
});
|
||||
|
||||
it('should warn if outerRadius/startAngle/endAngle is missing on a Wedge component', () => {
|
||||
expect(() => ReactTestRenderer.create(<Wedge fill="blue" />)).toErrorDev([
|
||||
'Warning: Failed prop type: The prop `outerRadius` is marked as required in `Wedge`, ' +
|
||||
'but its value is `undefined`.' +
|
||||
'\n in Wedge (at **)',
|
||||
'Warning: Failed prop type: The prop `startAngle` is marked as required in `Wedge`, ' +
|
||||
'but its value is `undefined`.' +
|
||||
'\n in Wedge (at **)',
|
||||
'Warning: Failed prop type: The prop `endAngle` is marked as required in `Wedge`, ' +
|
||||
'but its value is `undefined`.' +
|
||||
'\n in Wedge (at **)',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -433,14 +433,11 @@ describe('ReactFunctionComponent', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// TODO: change this test after we deprecate default props support
|
||||
// for function components
|
||||
it('should support default props and prop types', async () => {
|
||||
it('should support default props', async () => {
|
||||
function Child(props) {
|
||||
return <div>{props.test}</div>;
|
||||
}
|
||||
Child.defaultProps = {test: 2};
|
||||
Child.propTypes = {test: PropTypes.string};
|
||||
|
||||
await expect(async () => {
|
||||
const container = document.createElement('div');
|
||||
|
|
@ -451,9 +448,6 @@ describe('ReactFunctionComponent', () => {
|
|||
});
|
||||
}).toErrorDev([
|
||||
'Warning: Child: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead.',
|
||||
'Warning: Failed prop type: Invalid prop `test` of type `number` ' +
|
||||
'supplied to `Child`, expected `string`.\n' +
|
||||
' in Child (at **)',
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
'use strict';
|
||||
|
||||
let act;
|
||||
let PropTypes;
|
||||
let React;
|
||||
let ReactDOMClient;
|
||||
|
||||
|
|
@ -22,7 +21,6 @@ describe('ReactElementClone', () => {
|
|||
|
||||
act = require('internal-test-utils').act;
|
||||
|
||||
PropTypes = require('prop-types');
|
||||
React = require('react');
|
||||
ReactDOMClient = require('react-dom/client');
|
||||
|
||||
|
|
@ -335,41 +333,6 @@ describe('ReactElementClone', () => {
|
|||
React.cloneElement(<div />, null, [{}, {}]);
|
||||
});
|
||||
|
||||
it('should check declared prop types after clone', async () => {
|
||||
class Component extends React.Component {
|
||||
static propTypes = {
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
render() {
|
||||
return React.createElement('div', null, 'My color is ' + this.color);
|
||||
}
|
||||
}
|
||||
class Parent extends React.Component {
|
||||
render() {
|
||||
return React.cloneElement(this.props.child, {color: 123});
|
||||
}
|
||||
}
|
||||
class GrandParent extends React.Component {
|
||||
render() {
|
||||
return React.createElement(Parent, {
|
||||
child: React.createElement(Component, {color: 'red'}),
|
||||
});
|
||||
}
|
||||
}
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await expect(
|
||||
async () =>
|
||||
await act(() => root.render(React.createElement(GrandParent))),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `Component`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent',
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore key and ref warning getters', () => {
|
||||
const elementA = React.createElement('div');
|
||||
const elementB = React.cloneElement(elementA, elementA.props);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
// that do use JSX syntax. We should port them to React.createElement, and also
|
||||
// confirm there's a corresponding test that uses JSX syntax.
|
||||
|
||||
let PropTypes;
|
||||
let React;
|
||||
let ReactDOMClient;
|
||||
let act;
|
||||
|
|
@ -28,7 +27,6 @@ describe('ReactElementValidator', () => {
|
|||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
PropTypes = require('prop-types');
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
React = require('react');
|
||||
|
|
@ -221,26 +219,19 @@ describe('ReactElementValidator', () => {
|
|||
React.createElement(ComponentClass, null, [{}, {}]);
|
||||
});
|
||||
|
||||
it('should give context for PropType errors in nested components.', async () => {
|
||||
// In this test, we're making sure that if a proptype error is found in a
|
||||
// component, we give a small hint as to which parent instantiated that
|
||||
// component as per warnings about key usage in ReactElementValidator.
|
||||
function MyComp(props) {
|
||||
return React.createElement('div', null, 'My color is ' + props.color);
|
||||
it('should give context for errors in nested components.', async () => {
|
||||
function MyComp() {
|
||||
return [React.createElement('div')];
|
||||
}
|
||||
MyComp.propTypes = {
|
||||
color: PropTypes.string,
|
||||
};
|
||||
function ParentComp() {
|
||||
return React.createElement(MyComp, {color: 123});
|
||||
return React.createElement(MyComp);
|
||||
}
|
||||
await expect(async () => {
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await act(() => root.render(React.createElement(ParentComp)));
|
||||
}).toErrorDev(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
'Each child in a list should have a unique "key" prop. ' +
|
||||
'See https://reactjs.org/link/warning-keys for more information.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in ParentComp (at **)',
|
||||
);
|
||||
|
|
@ -328,125 +319,6 @@ describe('ReactElementValidator', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('should check default prop values', async () => {
|
||||
class Component extends React.Component {
|
||||
static propTypes = {prop: PropTypes.string.isRequired};
|
||||
static defaultProps = {prop: null};
|
||||
render() {
|
||||
return React.createElement('span', null, this.props.prop);
|
||||
}
|
||||
}
|
||||
|
||||
await expect(async () => {
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await act(() => root.render(React.createElement(Component)));
|
||||
}).toErrorDev(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`Component`, but its value is `null`.\n' +
|
||||
' in Component',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not check the default for explicit null', async () => {
|
||||
class Component extends React.Component {
|
||||
static propTypes = {prop: PropTypes.string.isRequired};
|
||||
static defaultProps = {prop: 'text'};
|
||||
render() {
|
||||
return React.createElement('span', null, this.props.prop);
|
||||
}
|
||||
}
|
||||
|
||||
await expect(async () => {
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await act(() =>
|
||||
root.render(React.createElement(Component, {prop: null})),
|
||||
);
|
||||
}).toErrorDev(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`Component`, but its value is `null`.\n' +
|
||||
' in Component',
|
||||
);
|
||||
});
|
||||
|
||||
it('should check declared prop types', async () => {
|
||||
class Component extends React.Component {
|
||||
static propTypes = {
|
||||
prop: PropTypes.string.isRequired,
|
||||
};
|
||||
render() {
|
||||
return React.createElement('span', null, this.props.prop);
|
||||
}
|
||||
}
|
||||
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await expect(async () => {
|
||||
await act(() => root.render(React.createElement(Component)));
|
||||
await act(() => root.render(React.createElement(Component, {prop: 42})));
|
||||
}).toErrorDev([
|
||||
'Warning: Failed prop type: ' +
|
||||
'The prop `prop` is marked as required in `Component`, but its value ' +
|
||||
'is `undefined`.\n' +
|
||||
' in Component',
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `prop` of type `number` supplied to ' +
|
||||
'`Component`, expected `string`.\n' +
|
||||
' in Component',
|
||||
]);
|
||||
|
||||
// Should not error for strings
|
||||
await act(() =>
|
||||
root.render(React.createElement(Component, {prop: 'string'})),
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if a PropType creator is used as a PropType', async () => {
|
||||
class Component extends React.Component {
|
||||
static propTypes = {
|
||||
myProp: PropTypes.shape,
|
||||
};
|
||||
render() {
|
||||
return React.createElement('span', null, this.props.myProp.value);
|
||||
}
|
||||
}
|
||||
|
||||
await expect(async () => {
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await act(() =>
|
||||
root.render(React.createElement(Component, {myProp: {value: 'hi'}})),
|
||||
);
|
||||
}).toErrorDev(
|
||||
'Warning: Component: type specification of prop `myProp` is invalid; ' +
|
||||
'the type checker function must return `null` or an `Error` but ' +
|
||||
'returned a function. You may have forgotten to pass an argument to ' +
|
||||
'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
|
||||
'oneOfType, and shape all require an argument).',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if component declares PropTypes instead of propTypes', async () => {
|
||||
class MisspelledPropTypesComponent extends React.Component {
|
||||
static PropTypes = {
|
||||
prop: PropTypes.string,
|
||||
};
|
||||
render() {
|
||||
return React.createElement('span', null, this.props.prop);
|
||||
}
|
||||
}
|
||||
|
||||
await expect(async () => {
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
await act(() =>
|
||||
root.render(
|
||||
React.createElement(MisspelledPropTypesComponent, {prop: 'Hi'}),
|
||||
),
|
||||
);
|
||||
}).toErrorDev(
|
||||
'Warning: Component MisspelledPropTypesComponent declared `PropTypes` ' +
|
||||
'instead of `propTypes`. Did you misspell the property assignment?',
|
||||
{withoutStack: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('warns for fragments with illegal attributes', async () => {
|
||||
class Foo extends React.Component {
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,7 @@
|
|||
// TODO: All these warnings should become static errors using Flow instead
|
||||
// of dynamic errors when using JSX with Flow.
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let ReactDOMClient;
|
||||
let ReactTestUtils;
|
||||
let PropTypes;
|
||||
let act;
|
||||
|
||||
describe('ReactJSXElementValidator', () => {
|
||||
let Component;
|
||||
|
|
@ -25,12 +21,8 @@ describe('ReactJSXElementValidator', () => {
|
|||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
PropTypes = require('prop-types');
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMClient = require('react-dom/client');
|
||||
ReactTestUtils = require('react-dom/test-utils');
|
||||
act = require('internal-test-utils').act;
|
||||
|
||||
Component = class extends React.Component {
|
||||
render() {
|
||||
|
|
@ -44,7 +36,6 @@ describe('ReactJSXElementValidator', () => {
|
|||
}
|
||||
};
|
||||
RequiredPropComponent.displayName = 'RequiredPropComponent';
|
||||
RequiredPropComponent.propTypes = {prop: PropTypes.string.isRequired};
|
||||
});
|
||||
|
||||
it('warns for keys for arrays of elements in children position', () => {
|
||||
|
|
@ -150,70 +141,25 @@ describe('ReactJSXElementValidator', () => {
|
|||
void (<Component>{[{}, {}]}</Component>);
|
||||
});
|
||||
|
||||
it('should give context for PropType errors in nested components.', () => {
|
||||
// In this test, we're making sure that if a proptype error is found in a
|
||||
// component, we give a small hint as to which parent instantiated that
|
||||
// component as per warnings about key usage in ReactElementValidator.
|
||||
it('should give context for errors in nested components.', () => {
|
||||
class MyComp extends React.Component {
|
||||
render() {
|
||||
return <div>My color is {this.color}</div>;
|
||||
return [<div />];
|
||||
}
|
||||
}
|
||||
MyComp.propTypes = {
|
||||
color: PropTypes.string,
|
||||
};
|
||||
class ParentComp extends React.Component {
|
||||
render() {
|
||||
return <MyComp color={123} />;
|
||||
return <MyComp />;
|
||||
}
|
||||
}
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<ParentComp />)).toErrorDev(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
'Each child in a list should have a unique "key" prop. ' +
|
||||
'See https://reactjs.org/link/warning-keys for more information.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in ParentComp (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should update component stack after receiving next element', async () => {
|
||||
function MyComp() {
|
||||
return null;
|
||||
}
|
||||
MyComp.propTypes = {
|
||||
color: PropTypes.string,
|
||||
};
|
||||
function MiddleComp(props) {
|
||||
return <MyComp color={props.color} />;
|
||||
}
|
||||
function ParentComp(props) {
|
||||
if (props.warn) {
|
||||
// This element has a source thanks to JSX.
|
||||
return <MiddleComp color={42} />;
|
||||
}
|
||||
// This element has no source.
|
||||
return React.createElement(MiddleComp, {color: 'blue'});
|
||||
}
|
||||
|
||||
const container = document.createElement('div');
|
||||
const root = ReactDOMClient.createRoot(container);
|
||||
await act(() => {
|
||||
root.render(<ParentComp warn={false} />);
|
||||
});
|
||||
expect(() =>
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(<ParentComp warn={true} />);
|
||||
}),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in MiddleComp (at **)\n' +
|
||||
' in ParentComp (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('gives a helpful error when passing null, undefined, or boolean', () => {
|
||||
const Undefined = undefined;
|
||||
const Null = null;
|
||||
|
|
@ -246,122 +192,6 @@ describe('ReactJSXElementValidator', () => {
|
|||
void (<Div />);
|
||||
});
|
||||
|
||||
it('should check default prop values', () => {
|
||||
RequiredPropComponent.defaultProps = {prop: null};
|
||||
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<RequiredPropComponent />),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`RequiredPropComponent`, but its value is `null`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not check the default for explicit null', () => {
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop={null} />),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`RequiredPropComponent`, but its value is `null`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should check declared prop types', () => {
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<RequiredPropComponent />),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: ' +
|
||||
'The prop `prop` is marked as required in `RequiredPropComponent`, but ' +
|
||||
'its value is `undefined`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop={42} />),
|
||||
).toErrorDev(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `prop` of type `number` supplied to ' +
|
||||
'`RequiredPropComponent`, expected `string`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
|
||||
// Should not error for strings
|
||||
ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop="string" />);
|
||||
});
|
||||
|
||||
it('should warn on invalid prop types', () => {
|
||||
// Since there is no prevalidation step for ES6 classes, there is no hook
|
||||
// for us to issue a warning earlier than element creation when the error
|
||||
// actually occurs. Since this step is skipped in production, we should just
|
||||
// warn instead of throwing for this case.
|
||||
class NullPropTypeComponent extends React.Component {
|
||||
render() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
}
|
||||
}
|
||||
NullPropTypeComponent.propTypes = {
|
||||
prop: null,
|
||||
};
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<NullPropTypeComponent />),
|
||||
).toErrorDev(
|
||||
'NullPropTypeComponent: prop type `prop` is invalid; it must be a ' +
|
||||
'function, usually from the `prop-types` package,',
|
||||
);
|
||||
});
|
||||
|
||||
// @gate !disableLegacyContext || !__DEV__
|
||||
it('should not warn on invalid context types', () => {
|
||||
class NullContextTypeComponent extends React.Component {
|
||||
render() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
}
|
||||
}
|
||||
NullContextTypeComponent.contextTypes = {
|
||||
prop: null,
|
||||
};
|
||||
ReactTestUtils.renderIntoDocument(<NullContextTypeComponent />);
|
||||
});
|
||||
|
||||
it('should warn if getDefaultProps is specified on the class', () => {
|
||||
class GetDefaultPropsComponent extends React.Component {
|
||||
render() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
}
|
||||
}
|
||||
GetDefaultPropsComponent.getDefaultProps = () => ({
|
||||
prop: 'foo',
|
||||
});
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<GetDefaultPropsComponent />),
|
||||
).toErrorDev(
|
||||
'getDefaultProps is only used on classic React.createClass definitions.' +
|
||||
' Use a static property named `defaultProps` instead.',
|
||||
{withoutStack: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if component declares PropTypes instead of propTypes', () => {
|
||||
class MisspelledPropTypesComponent extends React.Component {
|
||||
render() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
}
|
||||
}
|
||||
MisspelledPropTypesComponent.PropTypes = {
|
||||
prop: PropTypes.string,
|
||||
};
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<MisspelledPropTypesComponent prop="hi" />,
|
||||
),
|
||||
).toErrorDev(
|
||||
'Warning: Component MisspelledPropTypesComponent declared `PropTypes` ' +
|
||||
'instead of `propTypes`. Did you misspell the property assignment?',
|
||||
{withoutStack: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('warns for fragments with illegal attributes', () => {
|
||||
class Foo extends React.Component {
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -12,15 +12,12 @@ import assign from 'shared/assign';
|
|||
import {
|
||||
getIteratorFn,
|
||||
REACT_ELEMENT_TYPE,
|
||||
REACT_FORWARD_REF_TYPE,
|
||||
REACT_MEMO_TYPE,
|
||||
REACT_FRAGMENT_TYPE,
|
||||
} from 'shared/ReactSymbols';
|
||||
import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
|
||||
import isValidElementType from 'shared/isValidElementType';
|
||||
import isArray from 'shared/isArray';
|
||||
import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
|
||||
import checkPropTypes from 'shared/checkPropTypes';
|
||||
import {enableRefAsProp} from 'shared/ReactFeatureFlags';
|
||||
|
||||
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
|
||||
|
|
@ -596,8 +593,6 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) {
|
|||
|
||||
if (type === REACT_FRAGMENT_TYPE) {
|
||||
validateFragmentProps(element);
|
||||
} else {
|
||||
validatePropTypes(element);
|
||||
}
|
||||
|
||||
return element;
|
||||
|
|
@ -768,8 +763,6 @@ export function createElement(type, config, children) {
|
|||
|
||||
if (type === REACT_FRAGMENT_TYPE) {
|
||||
validateFragmentProps(element);
|
||||
} else {
|
||||
validatePropTypes(element);
|
||||
}
|
||||
|
||||
return element;
|
||||
|
|
@ -930,7 +923,6 @@ export function cloneElement(element, config, children) {
|
|||
for (let i = 2; i < arguments.length; i++) {
|
||||
validateChildKeys(arguments[i], clonedElement.type);
|
||||
}
|
||||
validatePropTypes(clonedElement);
|
||||
|
||||
return clonedElement;
|
||||
}
|
||||
|
|
@ -1137,59 +1129,3 @@ function validateFragmentProps(fragment) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let propTypesMisspellWarningShown = false;
|
||||
|
||||
/**
|
||||
* Given an element, validate that its props follow the propTypes definition,
|
||||
* provided by the type.
|
||||
*
|
||||
* @param {ReactElement} element
|
||||
*/
|
||||
function validatePropTypes(element) {
|
||||
if (__DEV__) {
|
||||
const type = element.type;
|
||||
if (type === null || type === undefined || typeof type === 'string') {
|
||||
return;
|
||||
}
|
||||
if (type.$$typeof === REACT_CLIENT_REFERENCE) {
|
||||
return;
|
||||
}
|
||||
let propTypes;
|
||||
if (typeof type === 'function') {
|
||||
propTypes = type.propTypes;
|
||||
} else if (
|
||||
typeof type === 'object' &&
|
||||
(type.$$typeof === REACT_FORWARD_REF_TYPE ||
|
||||
// Note: Memo only checks outer props here.
|
||||
// Inner props are checked in the reconciler.
|
||||
type.$$typeof === REACT_MEMO_TYPE)
|
||||
) {
|
||||
propTypes = type.propTypes;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (propTypes) {
|
||||
// Intentionally inside to avoid triggering lazy initializers:
|
||||
const name = getComponentNameFromType(type);
|
||||
checkPropTypes(propTypes, element.props, 'prop', name, element);
|
||||
} else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
|
||||
propTypesMisspellWarningShown = true;
|
||||
// Intentionally inside to avoid triggering lazy initializers:
|
||||
const name = getComponentNameFromType(type);
|
||||
console.error(
|
||||
'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
|
||||
name || 'Unknown',
|
||||
);
|
||||
}
|
||||
if (
|
||||
typeof type.getDefaultProps === 'function' &&
|
||||
!type.getDefaultProps.isReactClassApproved
|
||||
) {
|
||||
console.error(
|
||||
'getDefaultProps is only used on classic React.createClass ' +
|
||||
'definitions. Use a static property named `defaultProps` instead.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const loggedTypeFailures: {[string]: boolean} = {};
|
||||
|
||||
import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
|
||||
|
||||
import ReactSharedInternals from 'shared/ReactSharedInternals';
|
||||
import hasOwnProperty from 'shared/hasOwnProperty';
|
||||
|
||||
const ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
|
||||
|
||||
function setCurrentlyValidatingElement(element: any) {
|
||||
if (__DEV__) {
|
||||
if (element) {
|
||||
const owner = element._owner;
|
||||
const stack = describeUnknownElementTypeFrameInDEV(
|
||||
element.type,
|
||||
owner ? owner.type : null,
|
||||
);
|
||||
ReactDebugCurrentFrame.setExtraStackFrame(stack);
|
||||
} else {
|
||||
ReactDebugCurrentFrame.setExtraStackFrame(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function checkPropTypes(
|
||||
typeSpecs: Object,
|
||||
values: Object,
|
||||
location: string,
|
||||
componentName: ?string,
|
||||
element?: any,
|
||||
): void {
|
||||
if (__DEV__) {
|
||||
// $FlowFixMe[incompatible-use] This is okay but Flow doesn't know it.
|
||||
const has = Function.call.bind(hasOwnProperty);
|
||||
for (const typeSpecName in typeSpecs) {
|
||||
if (has(typeSpecs, typeSpecName)) {
|
||||
let error;
|
||||
// Prop type validation may throw. In case they do, we don't want to
|
||||
// fail the render phase where it didn't fail before. So we log it.
|
||||
// After these have been cleaned up, we'll let them throw.
|
||||
try {
|
||||
// This is intentionally an invariant that gets caught. It's the same
|
||||
// behavior as without this statement except with a better message.
|
||||
if (typeof typeSpecs[typeSpecName] !== 'function') {
|
||||
// eslint-disable-next-line react-internal/prod-error-codes
|
||||
const err = Error(
|
||||
(componentName || 'React class') +
|
||||
': ' +
|
||||
location +
|
||||
' type `' +
|
||||
typeSpecName +
|
||||
'` is invalid; ' +
|
||||
'it must be a function, usually from the `prop-types` package, but received `' +
|
||||
typeof typeSpecs[typeSpecName] +
|
||||
'`.' +
|
||||
'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.',
|
||||
);
|
||||
err.name = 'Invariant Violation';
|
||||
throw err;
|
||||
}
|
||||
error = typeSpecs[typeSpecName](
|
||||
values,
|
||||
typeSpecName,
|
||||
componentName,
|
||||
location,
|
||||
null,
|
||||
'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED',
|
||||
);
|
||||
} catch (ex) {
|
||||
error = ex;
|
||||
}
|
||||
if (error && !(error instanceof Error)) {
|
||||
setCurrentlyValidatingElement(element);
|
||||
console.error(
|
||||
'%s: type specification of %s' +
|
||||
' `%s` is invalid; the type checker ' +
|
||||
'function must return `null` or an `Error` but returned a %s. ' +
|
||||
'You may have forgotten to pass an argument to the type checker ' +
|
||||
'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
|
||||
'shape all require an argument).',
|
||||
componentName || 'React class',
|
||||
location,
|
||||
typeSpecName,
|
||||
typeof error,
|
||||
);
|
||||
setCurrentlyValidatingElement(null);
|
||||
}
|
||||
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
|
||||
// Only monitor this failure once because there tends to be a lot of the
|
||||
// same error.
|
||||
loggedTypeFailures[error.message] = true;
|
||||
setCurrentlyValidatingElement(element);
|
||||
console.error('Failed %s type: %s', location, error.message);
|
||||
setCurrentlyValidatingElement(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user