src/lib/utils/propTypeInstanceOf.js
import PropTypes from 'react/lib/ReactPropTypes';
import ReactPropTypeLocationNames from 'react/lib/ReactPropTypeLocationNames';
import PropTypeError from './PropTypeError';
const ANONYMOUS = '<<anonymous>>';
// Returns class name of the object, if any.
function getClassName(propValue) {
if (!(propValue.constructor
&& (propValue.constructor.name || propValue.constructor.displayName))) {
return ANONYMOUS;
}
return propValue.constructor.name || propValue.constructor.displayName;
}
function createChainableTypeChecker(validate) {
function checkType(isRequired,
props,
propName,
_componentName,
location,
_propFullName,
...rest) {
const componentName = _componentName || ANONYMOUS;
const propFullName = _propFullName || propName;
if (props[propName] === undefined) {
const locationName = ReactPropTypeLocationNames[location];
if (isRequired) {
return new PropTypeError(
`The ${locationName} \`${propFullName}\` is marked as required in ` +
`\`${componentName}\`, but its value is \`undefined\`.`
);
}
return null;
}
return validate(props, propName, componentName, location, propFullName, ...rest);
}
const chainedCheckType = checkType.bind(null, false);
chainedCheckType.isRequired = checkType.bind(null, true);
return chainedCheckType;
}
function createInstanceTypeChecker(expectedClass) {
const originalInstanceOf = PropTypes.instanceOf(expectedClass);
function validate(props, propName, componentName, location, propFullName, ...rest) {
const originalResult = originalInstanceOf(props, propName,
componentName, location, propFullName, ...rest);
if (originalResult !== null) {
const locationName = ReactPropTypeLocationNames[location];
const expectedClassName = expectedClass.name || expectedClass.displayName || ANONYMOUS;
const actualClassName = getClassName(props[propName]);
return new PropTypeError(`Invalid ${locationName} \`${propFullName}\` of type ` +
`\`${actualClassName}\` supplied to \`${componentName}\`, expected ` +
`instance of \`${expectedClassName}\`.`);
}
return originalResult;
}
const typeChecker = createChainableTypeChecker(validate);
const _type = `${expectedClass.displayName || expectedClass.name
|| expectedClass._type || expectedClass}`;
typeChecker.toString = () => `${'```'} ${_type} ${'```'}`;
typeChecker.isRequired.toString = () => `${typeChecker.toString()} *${'```'} required ${'```'}*`;
typeChecker.displayName = _type;
typeChecker.isRequired.displayName = _type;
return typeChecker;
}
module.exports = createInstanceTypeChecker;