Fix implicit any error for Cascader

This commit is contained in:
Wei Zhu 2017-11-21 21:52:40 +08:00
parent 2fe2e35a52
commit ecaf3a0883
3 changed files with 48 additions and 35 deletions

View File

@ -23,7 +23,7 @@ Cascade selection box.
| allowClear | whether allow clear | boolean | true |
| changeOnSelect | change value on each selection if set to true, see above demo for details | boolean | false |
| className | additional css class | string | - |
| defaultValue | initial selected value | [CascaderOptionType](https://git.io/vMMoK)\[] | \[] |
| defaultValue | initial selected value | string\[] | \[] |
| disabled | whether disabled select | boolean | false |
| displayRender | render function of displaying selected options | `(label, selectedOptions) => ReactNode` | `label => label.join(' / ')` |
| expandTrigger | expand current item when click or hover, one of 'click' 'hover' | string | 'click' |
@ -37,7 +37,7 @@ Cascade selection box.
| showSearch | Whether show search input in single mode. | boolean\|object | false |
| size | input size, one of `large` `default` `small` | string | `default` |
| style | additional style | string | - |
| value | selected value | [CascaderOptionType](https://git.io/vMMoK)\[] | - |
| value | selected value | string\[] | - |
| onChange | callback when finishing cascader select | `(value, selectedOptions) => void` | - |
| onPopupVisibleChange | callback when popup shown or hidden | `(value) => void` | - |
| popupVisible | set visible of cascader popup | boolean | - |

View File

@ -9,16 +9,17 @@ import Icon from '../icon';
export interface CascaderOptionType {
value: string;
label: string;
label: React.ReactNode;
disabled?: boolean;
children?: Array<CascaderOptionType>;
__IS_FILTERED_OPTION?: boolean;
}
export type CascaderExpandTrigger = 'click' | 'hover';
export interface ShowSearchType {
filter?: (inputValue: string, path: CascaderOptionType[]) => boolean;
render?: (inputValue: string, path: CascaderOptionType[], prefixCls: string) => React.ReactNode;
render?: (inputValue: string, path: CascaderOptionType[], prefixCls: string | undefined) => React.ReactNode;
sort?: (a: CascaderOptionType[], b: CascaderOptionType[], inputValue: string) => number;
matchInputWidth?: boolean;
}
@ -27,9 +28,9 @@ export interface CascaderProps {
/** 可选项数据源 */
options: CascaderOptionType[];
/** 默认的选中项 */
defaultValue?: CascaderOptionType[];
defaultValue?: string[];
/** 指定选中项 */
value?: CascaderOptionType[];
value?: string[];
/** 选择完成后的回调 */
onChange?: (value: string[], selectedOptions?: CascaderOptionType[]) => void;
/** 选择后展示的渲染函数 */
@ -62,9 +63,18 @@ export interface CascaderProps {
prefixCls?: string;
inputPrefixCls?: string;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
popupVisible?: boolean;
}
function highlightKeyword(str: string, keyword: string, prefixCls: string) {
export interface CascaderState {
inputFocused: boolean;
inputValue: string;
value: string[];
popupVisible: boolean | undefined;
flattenOptions: CascaderOptionType[][];
}
function highlightKeyword(str: string, keyword: string, prefixCls: string | undefined) {
return str.split(keyword)
.map((node: string, index: number) => index === 0 ? node : [
<span className={`${prefixCls}-menu-item-keyword`} key="seperator">{keyword}</span>,
@ -72,28 +82,29 @@ function highlightKeyword(str: string, keyword: string, prefixCls: string) {
]);
}
function defaultFilterOption(inputValue, path) {
return path.some(option => option.label.indexOf(inputValue) > -1);
function defaultFilterOption(inputValue: string, path: CascaderOptionType[]) {
return path.some(option => (option.label as string).indexOf(inputValue) > -1);
}
function defaultRenderFilteredOption(inputValue, path, prefixCls) {
function defaultRenderFilteredOption(inputValue: string, path: CascaderOptionType[], prefixCls: string | undefined) {
return path.map(({ label }, index) => {
const node = label.indexOf(inputValue) > -1 ? highlightKeyword(label, inputValue, prefixCls) : label;
const node = (label as string).indexOf(inputValue) > -1 ?
highlightKeyword(label as string, inputValue, prefixCls) : label;
return index === 0 ? node : [' / ', node];
});
}
function defaultSortFilteredOption(a, b, inputValue) {
function callback(elem) {
return elem.label.indexOf(inputValue) > -1;
function defaultSortFilteredOption(a: any[], b: any[], inputValue: string) {
function callback(elem: CascaderOptionType) {
return (elem.label as string).indexOf(inputValue) > -1;
}
return a.findIndex(callback) - b.findIndex(callback);
}
const defaultDisplayRender = label => label.join(' / ');
const defaultDisplayRender = (label: string[]) => label.join(' / ');
export default class Cascader extends React.Component<CascaderProps, any> {
export default class Cascader extends React.Component<CascaderProps, CascaderState> {
static defaultProps = {
prefixCls: 'ant-cascader',
inputPrefixCls: 'ant-input',
@ -110,7 +121,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
private input: Input;
constructor(props) {
constructor(props: CascaderProps) {
super(props);
this.state = {
value: props.value || props.defaultValue || [],
@ -121,7 +132,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
};
}
componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps: CascaderProps) {
if ('value' in nextProps) {
this.setState({ value: nextProps.value || [] });
}
@ -133,7 +144,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
}
}
handleChange = (value, selectedOptions) => {
handleChange = (value: any, selectedOptions: any[]) => {
this.setState({ inputValue: '' });
if (selectedOptions[0].__IS_FILTERED_OPTION) {
const unwrappedValue = value[0];
@ -144,7 +155,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
this.setValue(value, selectedOptions);
}
handlePopupVisibleChange = (popupVisible) => {
handlePopupVisibleChange = (popupVisible: boolean) => {
if (!('popupVisible' in this.props)) {
this.setState({
popupVisible,
@ -165,7 +176,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
});
}
handleInputClick = (e) => {
handleInputClick = (e: React.MouseEvent<HTMLInputElement>) => {
const { inputFocused, popupVisible } = this.state;
// Prevent `Trigger` behaviour.
if (inputFocused || popupVisible) {
@ -174,18 +185,18 @@ export default class Cascader extends React.Component<CascaderProps, any> {
}
}
handleKeyDown = (e) => {
handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.keyCode === KeyCode.BACKSPACE) {
e.stopPropagation();
}
}
handleInputChange = (e) => {
handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
this.setState({ inputValue });
}
setValue = (value, selectedOptions = []) => {
setValue = (value: string[], selectedOptions: any[] = []) => {
if (!('value' in this.props)) {
this.setState({ value });
}
@ -199,12 +210,14 @@ export default class Cascader extends React.Component<CascaderProps, any> {
const { options, displayRender = defaultDisplayRender as Function } = this.props;
const value = this.state.value;
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
const selectedOptions = arrayTreeFilter(options, (o, level) => o.value === unwrappedValue[level]);
const selectedOptions: CascaderOptionType[] = arrayTreeFilter(options,
(o: CascaderOptionType, level: number) => o.value === unwrappedValue[level],
);
const label = selectedOptions.map(o => o.label);
return displayRender(label, selectedOptions);
}
clearSelection = (e) => {
clearSelection = (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.stopPropagation();
if (!this.state.inputValue) {
@ -215,7 +228,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
}
}
flattenTree(options, changeOnSelect, ancestor = []) {
flattenTree(options: CascaderOptionType[], changeOnSelect: boolean | undefined, ancestor: CascaderOptionType[] = []) {
let flattenOptions: any = [];
options.forEach((option) => {
const path = ancestor.concat(option);
@ -229,7 +242,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
return flattenOptions;
}
generateFilteredOptions(prefixCls) {
generateFilteredOptions(prefixCls: string | undefined) {
const { showSearch, notFoundContent } = this.props;
const {
filter = defaultFilterOption,
@ -241,14 +254,14 @@ export default class Cascader extends React.Component<CascaderProps, any> {
.sort((a, b) => sort(a, b, inputValue));
if (filtered.length > 0) {
return filtered.map((path) => {
return filtered.map((path: any) => {
return {
__IS_FILTERED_OPTION: true,
path,
label: render(inputValue, path, prefixCls),
value: path.map(o => o.value),
disabled: path.some(o => o.disabled),
};
value: path.map((o: CascaderOptionType) => o.value),
disabled: path.some((o: CascaderOptionType) => o.disabled),
} as CascaderOptionType;
});
}
return [{ label: notFoundContent, value: 'ANT_CASCADER_NOT_FOUND', disabled: true }];
@ -262,7 +275,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
this.input.blur();
}
saveInput = (node) => {
saveInput = (node: Input) => {
this.input = node;
}

View File

@ -24,7 +24,7 @@ subtitle: 级联选择
| allowClear | 是否支持清除 | boolean | true |
| changeOnSelect | 当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | boolean | false |
| className | 自定义类名 | string | - |
| defaultValue | 默认的选中项 | [CascaderOptionType](https://git.io/vMMoK)\[] | \[] |
| defaultValue | 默认的选中项 | string\[] | \[] |
| disabled | 禁用 | boolean | false |
| displayRender | 选择后展示的渲染函数 | `(label, selectedOptions) => ReactNode` | `label => label.join(' / ')` |
| expandTrigger | 次级菜单的展开方式,可选 'click' 和 'hover' | string | 'click' |
@ -38,7 +38,7 @@ subtitle: 级联选择
| showSearch | 在选择框中显示搜索框 | boolean | false |
| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
| style | 自定义样式 | string | - |
| value | 指定选中项 | [CascaderOptionType](https://git.io/vMMoK)\[] | - |
| value | 指定选中项 | string\[] | - |
| onChange | 选择完成后的回调 | `(value, selectedOptions) => void` | - |
| onPopupVisibleChange | 显示/隐藏浮层的回调 | `(value) => void` | - |
| popupVisible | 控制浮层显隐 | boolean | - |