Skip to content

Commit

Permalink
Merge pull request facebook#6377 from puradox/proptypes-symbol
Browse files Browse the repository at this point in the history
Add new primitive PropType `Symbol`
(cherry picked from commit 7bf96c0)
  • Loading branch information
gaearon authored and zpao committed Jun 8, 2016
1 parent 04862d5 commit d2635f2
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
23 changes: 23 additions & 0 deletions src/isomorphic/classic/types/ReactPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ var ReactPropTypes = {
number: createPrimitiveTypeChecker('number'),
object: createPrimitiveTypeChecker('object'),
string: createPrimitiveTypeChecker('string'),
symbol: createPrimitiveTypeChecker('symbol'),

any: createAnyTypeChecker(),
arrayOf: createArrayOfTypeChecker,
Expand Down Expand Up @@ -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;
Expand All @@ -418,6 +438,9 @@ function getPropType(propValue) {
// passes PropTypes.object.
return 'object';
}
if (isSymbol(propType, propValue)) {
return 'symbol';
}
return propType;
}

Expand Down
49 changes: 49 additions & 0 deletions src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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() {
Expand All @@ -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() {
Expand All @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit d2635f2

Please sign in to comment.