/
propTypes.js
71 lines (61 loc) · 1.84 KB
/
propTypes.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// @flow
import React from 'react';
import { isValidElementType, typeOf, Element, ForwardRef } from 'react-is';
import is from 'is-lite';
function createChainableTypeChecker(validate: Function): Function {
function checkType(
isRequired: boolean,
props: Object,
propName: string,
componentName: string,
location: string,
propFullName: ?string,
...args: Array<*>
): ?Error {
const componentNameSafe = componentName || '<<anonymous>>';
const propFullNameSafe = propFullName || propName;
/* istanbul ignore else */
if (props[propName] == null) {
if (isRequired) {
return new Error(
`Required ${location} \`${propFullNameSafe}\` was not specified in \`${componentNameSafe}\`.`,
);
}
return null;
}
return validate(props, propName, componentNameSafe, location, propFullNameSafe, ...args);
}
const chainedCheckType = checkType.bind(null, false);
chainedCheckType.isRequired = checkType.bind(null, true);
return chainedCheckType;
}
export const componentTypeWithRefs = createChainableTypeChecker(
(
props: Object,
propName: string,
componentName: string,
location: string,
propFullName: string,
): any => {
const propValue = props[propName];
let Component = propValue;
if (!React.isValidElement(propValue) && isValidElementType(propValue)) {
const ownProps = {
ref: () => {},
step: {},
};
Component = <Component {...ownProps} />;
}
if (
is.string(propValue) ||
is.number(propValue) ||
!isValidElementType(propValue) ||
![Element, ForwardRef].includes(typeOf(Component))
) {
return new Error(
`Invalid ${location} \`${propFullName}\` supplied to \`${componentName}\`. Expected a React class or forwardRef.`,
);
}
return undefined;
},
);