Add PropTypes.component to demand a single React component.
cpojer committed
Jan 9, 2014 at 11:39 UTC
b713c2c6968d7513305ea5285825698c2eab90c5
2 files changed
+75
-1
src/core/ReactPropTypes.js
+21
-1
@@ -86,7 +86,8 @@ var Props = {
86
87
instanceOf: createInstanceTypeChecker,
88
89
- renderable: createRenderableTypeChecker()
89
+ renderable: createRenderableTypeChecker(),
90
+ component: createComponentTypeChecker()
91
92
};
93
@@ -200,6 +201,25 @@ function createRenderableTypeChecker() {
201
return createChainableTypeChecker(validateRenderableType);
202
}
203
204
+function createComponentTypeChecker() {
205
+ function validateComponentType(
206
+ shouldThrow, propValue, propName, componentName, location
207
+ ) {
208
+ var isValid = ReactComponent.isValidComponent(propValue);
209
+ if (!shouldThrow) {
210
+ return isValid;
211
+ }
212
+ invariant(
213
+ isValid,
214
+ 'Invalid %s `%s` supplied to `%s`, expected a React component.',
215
+ ReactPropTypeLocationNames[location],
216
+ propName,
217
+ componentName
218
+ );
219
+ }
220
+ return createChainableTypeChecker(validateComponentType);
221
+}
222
+
223
function createChainableTypeChecker(validate) {
224
function checkType(
225
isRequired, shouldThrow, props, propName, componentName, location
src/core/__tests__/ReactPropTypes-test.js
+54
@@ -19,6 +19,8 @@
19
20
"use strict";
21
22
+var ReactTestUtils;
23
+
24
var Props = require('ReactPropTypes');
25
var React = require('React');
26
var ReactPropTypeLocations = require('ReactPropTypeLocations');
@@ -46,6 +48,8 @@ var MyComponent = React.createClass({
48
describe('Primitive Types', function() {
49
beforeEach(function() {
50
require('mock-modules').dumpCache();
51
+
52
+ ReactTestUtils = require('ReactTestUtils');
53
});
54
55
it("should throw for invalid strings", function() {
@@ -170,6 +174,56 @@ describe('Instance Types', function() {
174
});
175
});
176
177
+describe('Component Type', function() {
178
+ it('should support components', () => {
179
+ expect(typeCheck(Props.component, <div />)).not.toThrow();
180
+ });
181
+
182
+ it('should not support multiple components or scalar values', () => {
183
+ [[<div />, <div />], 123, 'foo', false].forEach((value) => {
184
+ expect(typeCheck(Props.component, value)).toThrow();
185
+ });
186
+ });
187
+
188
+ var Component = React.createClass({
189
+ propTypes: {
190
+ children: Props.component.isRequired
191
+ },
192
+
193
+ render: function() {
194
+ return <div>{this.props.children}</div>;
195
+ }
196
+ });
197
+
198
+ it('should be able to define a single child as children', () => {
199
+ expect(() => {
200
+ var instance =
201
+ <Component>
202
+ <div />
203
+ </Component>;
204
+ ReactTestUtils.renderIntoDocument(instance);
205
+ }).not.toThrow();
206
+ });
207
+
208
+ it('should throw when passing more than one child', () => {
209
+ expect(() => {
210
+ var instance =
211
+ <Component>
212
+ <div />
213
+ <div />
214
+ </Component>;
215
+ ReactTestUtils.renderIntoDocument(instance);
216
+ }).toThrow();
217
+ });
218
+
219
+ it('should throw when passing no children and isRequired is set', () => {
220
+ expect(() => {
221
+ var instance = <Component />;
222
+ ReactTestUtils.renderIntoDocument(instance);
223
+ }).toThrow();
224
+ });
225
+});
226
+
227
describe('Union Types', function() {
228
beforeEach(function() {
229
require('mock-modules').dumpCache();