diff --git a/src/PropTypes.js b/src/PropTypes.js
new file mode 100644
index 000000000..9317e2c81
--- /dev/null
+++ b/src/PropTypes.js
@@ -0,0 +1,66 @@
+import { PropTypes } from 'react';
+
+function valueType(props, propName, componentName) {
+ const labelInValueShape = PropTypes.shape({
+ key: PropTypes.string.isRequired,
+ label: PropTypes.string,
+ });
+ if (props.labelInValue) {
+ const validate = PropTypes.oneOfType([
+ PropTypes.arrayOf(labelInValueShape),
+ labelInValueShape,
+ ]);
+ const error = validate(...arguments);
+ if (error) {
+ return new Error(
+ `Invalid prop \`${propName}\` supplied to \`${componentName}\`, ` +
+ `when you set \`labelInValue\` to \`true\`, \`${propName}\` should in ` +
+ `shape of \`{ key: string, label?: string }\`.`
+ );
+ }
+ } else if (props.multiple && props[propName] === '') {
+ return new Error(
+ `Invalid prop \`${propName}\` of type \`string\` supplied to \`${componentName}\`, ` +
+ `expected \`array\` when \`multiple\` is \`true\`.`
+ );
+ } else {
+ const validate = PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.string),
+ PropTypes.string,
+ ]);
+ return validate(...arguments);
+ }
+}
+
+export const SelectPropTypes = {
+ defaultActiveFirstOption: PropTypes.bool,
+ multiple: PropTypes.bool,
+ filterOption: PropTypes.any,
+ children: PropTypes.any,
+ showSearch: PropTypes.bool,
+ disabled: PropTypes.bool,
+ allowClear: PropTypes.bool,
+ showArrow: PropTypes.bool,
+ tags: PropTypes.bool,
+ prefixCls: PropTypes.string,
+ className: PropTypes.string,
+ transitionName: PropTypes.string,
+ optionLabelProp: PropTypes.string,
+ optionFilterProp: PropTypes.string,
+ animation: PropTypes.string,
+ choiceTransitionName: PropTypes.string,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ onFocus: PropTypes.func,
+ onSelect: PropTypes.func,
+ onSearch: PropTypes.func,
+ placeholder: PropTypes.any,
+ onDeselect: PropTypes.func,
+ labelInValue: PropTypes.bool,
+ value: valueType,
+ defaultValue: valueType,
+ dropdownStyle: PropTypes.object,
+ maxTagTextLength: PropTypes.number,
+ tokenSeparators: PropTypes.arrayOf(PropTypes.string),
+ getInputElement: PropTypes.func,
+};
diff --git a/src/Select.jsx b/src/Select.jsx
index 2e936b481..d7a8eba78 100644
--- a/src/Select.jsx
+++ b/src/Select.jsx
@@ -1,4 +1,4 @@
-import React, { PropTypes } from 'react';
+import React from 'react';
import ReactDOM from 'react-dom';
import KeyCode from 'rc-util/lib/KeyCode';
import classnames from 'classnames';
@@ -15,6 +15,7 @@ import {
} from './util';
import SelectTrigger from './SelectTrigger';
import FilterMixin from './FilterMixin';
+import { SelectPropTypes } from './PropTypes';
function noop() {
}
@@ -27,57 +28,8 @@ function saveRef(name, component) {
this[name] = component;
}
-let valueObjectShape;
-
-if (PropTypes) {
- valueObjectShape = PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.shape({
- key: PropTypes.string,
- label: PropTypes.node,
- }),
- ]);
-}
-
const Select = React.createClass({
- propTypes: {
- defaultActiveFirstOption: PropTypes.bool,
- multiple: PropTypes.bool,
- filterOption: PropTypes.any,
- children: PropTypes.any,
- showSearch: PropTypes.bool,
- disabled: PropTypes.bool,
- allowClear: PropTypes.bool,
- showArrow: PropTypes.bool,
- tags: PropTypes.bool,
- prefixCls: PropTypes.string,
- className: PropTypes.string,
- transitionName: PropTypes.string,
- optionLabelProp: PropTypes.string,
- optionFilterProp: PropTypes.string,
- animation: PropTypes.string,
- choiceTransitionName: PropTypes.string,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- onFocus: PropTypes.func,
- onSelect: PropTypes.func,
- onSearch: PropTypes.func,
- placeholder: PropTypes.any,
- onDeselect: PropTypes.func,
- labelInValue: PropTypes.bool,
- value: PropTypes.oneOfType([
- valueObjectShape,
- PropTypes.arrayOf(valueObjectShape),
- ]),
- defaultValue: PropTypes.oneOfType([
- valueObjectShape,
- PropTypes.arrayOf(valueObjectShape),
- ]),
- dropdownStyle: PropTypes.object,
- maxTagTextLength: PropTypes.number,
- tokenSeparators: PropTypes.arrayOf(PropTypes.string),
- getInputElement: PropTypes.func,
- },
+ propTypes: SelectPropTypes,
mixins: [FilterMixin],
@@ -91,7 +43,6 @@ const Select = React.createClass({
showSearch: true,
allowClear: false,
placeholder: '',
- defaultValue: [],
onChange: noop,
onFocus: noop,
onBlur: noop,
diff --git a/tests/Select.spec.js b/tests/Select.spec.js
index f4a7b9078..7580f5963 100644
--- a/tests/Select.spec.js
+++ b/tests/Select.spec.js
@@ -441,4 +441,38 @@ describe('Select', () => {
dropdownWrapper.find('MenuItem').first().simulate('click');
expect(wrapper.state().inputValue).toBe('1');
});
+
+ describe('propTypes', () => {
+ const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
+
+ beforeEach(() => {
+ spy.mockReset();
+ });
+
+ afterAll(() => {
+ spy.mockRestore();
+ });
+
+ it('warns on invalid value when labelInValue', () => {
+ expect(() => {
+ mount(
+
+ );
+ }).toThrow();
+ expect(spy.mock.calls[0][0]).toMatch(
+ 'Invalid prop `value` supplied to `Select`, when you set `labelInValue` ' +
+ 'to `true`, `value` should in shape of `{ key: string, label?: string }`'
+ );
+ });
+
+ it('warns on invalid value when multiple', () => {
+ mount(
+
+ );
+ expect(spy.mock.calls[0][0]).toMatch(
+ 'Invalid prop `value` of type `string` supplied to `Select`, ' +
+ 'expected `array` when `multiple` is `true`'
+ );
+ });
+ });
});