From ecaf3a08838d5db2c2dad2bcc6d6b434d291b433 Mon Sep 17 00:00:00 2001 From: Wei Zhu Date: Tue, 21 Nov 2017 21:52:40 +0800 Subject: [PATCH] Fix implicit any error for Cascader --- components/cascader/index.en-US.md | 4 +- components/cascader/index.tsx | 75 ++++++++++++++++++------------ components/cascader/index.zh-CN.md | 4 +- 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/components/cascader/index.en-US.md b/components/cascader/index.en-US.md index b0be1cbff3..ff30cc16b2 100644 --- a/components/cascader/index.en-US.md +++ b/components/cascader/index.en-US.md @@ -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 | - | diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index bf7245fc5b..6fab2ea3a5 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -9,16 +9,17 @@ import Icon from '../icon'; export interface CascaderOptionType { value: string; - label: string; + label: React.ReactNode; disabled?: boolean; children?: Array; + __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 : [ {keyword}, @@ -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 { +export default class Cascader extends React.Component { static defaultProps = { prefixCls: 'ant-cascader', inputPrefixCls: 'ant-input', @@ -110,7 +121,7 @@ export default class Cascader extends React.Component { 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 { }; } - 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 { } } - 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 { 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 { }); } - handleInputClick = (e) => { + handleInputClick = (e: React.MouseEvent) => { const { inputFocused, popupVisible } = this.state; // Prevent `Trigger` behaviour. if (inputFocused || popupVisible) { @@ -174,18 +185,18 @@ export default class Cascader extends React.Component { } } - handleKeyDown = (e) => { + handleKeyDown = (e: React.KeyboardEvent) => { if (e.keyCode === KeyCode.BACKSPACE) { e.stopPropagation(); } } - handleInputChange = (e) => { + handleInputChange = (e: React.ChangeEvent) => { 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 { 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) => { e.preventDefault(); e.stopPropagation(); if (!this.state.inputValue) { @@ -215,7 +228,7 @@ export default class Cascader extends React.Component { } } - 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 { 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 { .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 { this.input.blur(); } - saveInput = (node) => { + saveInput = (node: Input) => { this.input = node; } diff --git a/components/cascader/index.zh-CN.md b/components/cascader/index.zh-CN.md index e2b43ea824..66ce04c694 100644 --- a/components/cascader/index.zh-CN.md +++ b/components/cascader/index.zh-CN.md @@ -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 | - |