Merge pull request #6377 from puradox/proptypes-symbol

Add new primitive PropType `Symbol`
(cherry picked from commit 7bf96c08e6)
This commit is contained in:
Dan Abramov
2016-06-14 15:30:25 -07:00
committed by Paul O’Shannessy
parent 2ef148d1ee
commit f112083c7a
3 changed files with 73 additions and 0 deletions
+1
View File
@@ -33,6 +33,7 @@
"browserify": "^13.0.0",
"bundle-collapser": "^1.1.1",
"coffee-script": "^1.8.0",
"core-js": "^2.2.1",
"coveralls": "^2.11.6",
"del": "^2.0.2",
"derequire": "^2.0.3",
@@ -73,6 +73,7 @@ var ReactPropTypes = {
number: createPrimitiveTypeChecker('number'),
object: createPrimitiveTypeChecker('object'),
string: createPrimitiveTypeChecker('string'),
symbol: createPrimitiveTypeChecker('symbol'),
any: createAnyTypeChecker(),
arrayOf: createArrayOfTypeChecker,
@@ -406,6 +407,25 @@ function isNode(propValue) {
}
}
function isSymbol(propType, propValue) {
// Native Symbol.
if (propType === 'symbol') {
return true;
}
// 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
if (propValue['@@toStringTag'] === 'Symbol') {
return true;
}
// Fallback for non-spec compliant Symbols which are polyfilled.
if (typeof Symbol === 'function' && propValue instanceof Symbol) {
return true;
}
return false;
}
// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
var propType = typeof propValue;
@@ -418,6 +438,9 @@ function getPropType(propValue) {
// passes PropTypes.object.
return 'object';
}
if (isSymbol(propType, propValue)) {
return 'symbol';
}
return propType;
}
@@ -80,6 +80,12 @@ describe('ReactPropTypes', function() {
'Invalid prop `testProp` of type `object` supplied to ' +
'`testComponent`, expected `string`.'
);
typeCheckFail(
PropTypes.string,
Symbol(),
'Invalid prop `testProp` of type `symbol` supplied to ' +
'`testComponent`, expected `string`.'
);
});
it('should fail date and regexp correctly', function() {
@@ -106,6 +112,7 @@ describe('ReactPropTypes', function() {
typeCheckPass(PropTypes.object, {});
typeCheckPass(PropTypes.object, new Date());
typeCheckPass(PropTypes.object, /please/);
typeCheckPass(PropTypes.symbol, Symbol());
});
it('should be implicitly optional and not warn without values', function() {
@@ -124,6 +131,7 @@ describe('ReactPropTypes', function() {
typeCheckPass(PropTypes.any, 0);
typeCheckPass(PropTypes.any, 'str');
typeCheckPass(PropTypes.any, []);
typeCheckPass(PropTypes.any, Symbol());
});
it('should be implicitly optional and not warn without values', function() {
@@ -150,6 +158,7 @@ describe('ReactPropTypes', function() {
typeCheckPass(PropTypes.arrayOf(PropTypes.number), [1, 2, 3]);
typeCheckPass(PropTypes.arrayOf(PropTypes.string), ['a', 'b', 'c']);
typeCheckPass(PropTypes.arrayOf(PropTypes.oneOf(['a', 'b'])), ['a', 'b']);
typeCheckPass(PropTypes.arrayOf(PropTypes.symbol), [Symbol(), Symbol()]);
});
it('should support arrayOf with complex types', function() {
@@ -490,6 +499,10 @@ describe('ReactPropTypes', function() {
PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
{a: 'a', b: 'b'}
);
typeCheckPass(
PropTypes.objectOf(PropTypes.symbol),
{a: Symbol(), b: Symbol(), c: Symbol()}
);
});
it('should support objectOf with complex types', function() {
@@ -545,6 +558,12 @@ describe('ReactPropTypes', function() {
'Invalid prop `testProp` of type `string` supplied to ' +
'`testComponent`, expected an object.'
);
typeCheckFail(
PropTypes.objectOf(PropTypes.symbol),
Symbol(),
'Invalid prop `testProp` of type `symbol` supplied to ' +
'`testComponent`, expected an object.'
);
});
it('should not warn when passing an empty object', function() {
@@ -782,6 +801,36 @@ describe('ReactPropTypes', function() {
});
});
describe('Symbol Type', function() {
it('should warn for non-symbol', function() {
typeCheckFail(
PropTypes.symbol,
'hello',
'Invalid prop `testProp` of type `string` supplied to ' +
'`testComponent`, expected `symbol`.'
);
typeCheckFail(
PropTypes.symbol,
function() { },
'Invalid prop `testProp` of type `function` supplied to ' +
'`testComponent`, expected `symbol`.'
);
typeCheckFail(
PropTypes.symbol,
{
'@@toStringTag': 'Katana',
},
'Invalid prop `testProp` of type `object` supplied to ' +
'`testComponent`, expected `symbol`.'
);
});
it('should not warn for a polyfilled Symbol', function() {
var CoreSymbol = require('core-js/library/es6/symbol');
typeCheckPass(PropTypes.symbol, CoreSymbol('core-js'));
});
});
describe('Custom validator', function() {
beforeEach(function() {
jest.resetModuleRegistry();