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 | | allowClear | whether allow clear | boolean | true |
| changeOnSelect | change value on each selection if set to true, see above demo for details | boolean | false | | changeOnSelect | change value on each selection if set to true, see above demo for details | boolean | false |
| className | additional css class | string | - | | 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 | | disabled | whether disabled select | boolean | false |
| displayRender | render function of displaying selected options | `(label, selectedOptions) => ReactNode` | `label => label.join(' / ')` | | 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' | | 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 | | showSearch | Whether show search input in single mode. | boolean\|object | false |
| size | input size, one of `large` `default` `small` | string | `default` | | size | input size, one of `large` `default` `small` | string | `default` |
| style | additional style | string | - | | 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` | - | | onChange | callback when finishing cascader select | `(value, selectedOptions) => void` | - |
| onPopupVisibleChange | callback when popup shown or hidden | `(value) => void` | - | | onPopupVisibleChange | callback when popup shown or hidden | `(value) => void` | - |
| popupVisible | set visible of cascader popup | boolean | - | | popupVisible | set visible of cascader popup | boolean | - |

View File

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

View File

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