Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"browserify": "^12.0.1",
"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 @@ -487,6 +496,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 @@ -542,6 +555,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 @@ -779,6 +798,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