From 08e21e0a2f734069faea4857329c64ca4b42287a Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Mon, 24 Oct 2016 16:30:38 +0800 Subject: [PATCH] refactor: close: #3490 --- components/radio/group.tsx | 16 +++-- components/radio/radio.tsx | 2 +- components/select/index.tsx | 4 +- components/switch/index.tsx | 2 +- .../table/FilterDropdownMenuWrapper.tsx | 13 ++++ components/table/Table.tsx | 67 +++++++++++-------- components/table/filterDropdown.tsx | 10 +-- components/table/util.tsx | 4 +- components/tabs/index.tsx | 31 ++++++--- components/tag/index.tsx | 13 ++-- components/time-picker/index.tsx | 8 +-- components/tooltip/index.tsx | 6 +- components/transfer/index.tsx | 30 ++++----- components/transfer/list.tsx | 25 +++---- components/transfer/search.tsx | 16 +++-- components/tree-select/index.tsx | 2 +- components/upload/index.tsx | 22 +++--- components/upload/uploadList.tsx | 17 +++-- tsconfig.json | 2 +- 19 files changed, 163 insertions(+), 127 deletions(-) create mode 100644 components/table/FilterDropdownMenuWrapper.tsx diff --git a/components/radio/group.tsx b/components/radio/group.tsx index ffbc3fa784..b20d6310e1 100644 --- a/components/radio/group.tsx +++ b/components/radio/group.tsx @@ -33,10 +33,7 @@ export interface RadioGroupProps { export default class RadioGroup extends React.Component { static defaultProps = { - prefixCls: 'ant-radio-group', disabled: false, - onChange() { - }, }; constructor(props) { super(props); @@ -76,11 +73,15 @@ export default class RadioGroup extends React.Component { value: ev.target.value, }); } - this.props.onChange(ev); + + const onChange = this.props.onChange; + if (onChange) { + onChange(ev); + } } render() { const props = this.props; - const children = React.Children.map(props.children, (radio: any) => { + const children = React.Children.map((props.children || {}), (radio: any) => { if (radio && (radio.type === Radio || radio.type === RadioButton) && radio.props) { const keyProps = {}; if (!('key' in radio) && typeof radio.props.value === 'string') { @@ -94,9 +95,10 @@ export default class RadioGroup extends React.Component { } return radio; }); + const prefixCls = props.prefixCls || 'ant-radio-group'; const classString = classNames({ - [props.prefixCls]: true, - [`${props.prefixCls}-${props.size}`]: props.size, + [prefixCls]: true, + [`${prefixCls}-${props.size}`]: props.size, }); return
{children}
; } diff --git a/components/radio/radio.tsx b/components/radio/radio.tsx index c349c73340..a0f065130d 100644 --- a/components/radio/radio.tsx +++ b/components/radio/radio.tsx @@ -28,7 +28,7 @@ export default class Radio extends React.Component { return PureRenderMixin.shouldComponentUpdate.apply(this, args); } render() { - const { prefixCls, children, checked, disabled, className, style } = this.props; + const { prefixCls, children, checked, disabled, className = '', style } = this.props; const wrapperClassString = classNames({ [`${prefixCls}-wrapper`]: true, [`${prefixCls}-wrapper-checked`]: checked, diff --git a/components/select/index.tsx b/components/select/index.tsx index 8c5323e3b8..fb561948d8 100755 --- a/components/select/index.tsx +++ b/components/select/index.tsx @@ -13,7 +13,7 @@ export interface SelectProps { defaultValue?: SelectValue; size?: 'default' | 'large' | 'small'; combobox?: boolean; - notFoundContent?: React.ReactNode | string; + notFoundContent?: React.ReactNode | null; showSearch?: boolean; transitionName?: string; choiceTransitionName?: string; @@ -84,7 +84,7 @@ export default class Select extends React.Component { render() { const { prefixCls, - className, + className = '', size, combobox, showSearch, diff --git a/components/switch/index.tsx b/components/switch/index.tsx index 993152aa3d..fa76c8f3e1 100755 --- a/components/switch/index.tsx +++ b/components/switch/index.tsx @@ -28,7 +28,7 @@ export default class Switch extends React.Component { }; render() { - const { prefixCls, size, className } = this.props; + const { prefixCls, size, className = '' } = this.props; const classes = classNames({ [className]: !!className, [`${prefixCls}-small`]: size === 'small', diff --git a/components/table/FilterDropdownMenuWrapper.tsx b/components/table/FilterDropdownMenuWrapper.tsx new file mode 100644 index 0000000000..1709a0e910 --- /dev/null +++ b/components/table/FilterDropdownMenuWrapper.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +export interface FilterDropdownMenuWrapperProps { + onClick?: React.MouseEventHandler; + children?: any; + className?: string; +} +export default class FilterDropdownMenuWrapper extends React.Component { + render() { + const { onClick, children, className } = this.props; + return
{children}
; + } +} diff --git a/components/table/Table.tsx b/components/table/Table.tsx index e616a630d0..bd70aaa764 100755 --- a/components/table/Table.tsx +++ b/components/table/Table.tsx @@ -68,7 +68,7 @@ export interface TableProps { pagination?: PaginationProps | boolean; size?: 'default' | 'small'; dataSource?: Object[]; - columns?: TableColumnConfig[]; + columns: TableColumnConfig[]; rowKey?: string | ((record: Object, index: number) => string); rowClassName?: (record: Object, index: number) => string; expandedRowRender?: any; @@ -87,7 +87,7 @@ export interface TableProps { footer?: (currentPageData: Object[]) => React.ReactNode; title?: (currentPageData: Object[]) => React.ReactNode; scroll?: { x?: boolean | number, y?: boolean | number}; - childrenColumnName?: 'string'; + childrenColumnName?: string; bodyStyle?: React.CSSProperties; className?: string; } @@ -117,7 +117,6 @@ export default class Table extends React.Component { static defaultProps = { dataSource: [], prefixCls: 'ant-table', - dropdownPrefixCls: 'ant-dropdown', useFixedHeader: false, rowSelection: null, className: '', @@ -125,10 +124,8 @@ export default class Table extends React.Component { loading: false, bordered: false, indentSize: 20, - onChange: noop, locale: {}, rowKey: 'key', - childrenColumnName: 'children', }; static contextTypes = { @@ -361,7 +358,10 @@ export default class Table extends React.Component { this.setState(newState); } - this.props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, newState))); + const onChange = this.props.onChange; + if (onChange) { + onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, newState))); + } } handleFilter = (column, nextFilters) => { @@ -409,11 +409,14 @@ export default class Table extends React.Component { } this.setState(newState, () => { - props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, { - selectionDirty: false, - filters, - pagination, - }))); + const onChange = this.props.onChange; + if (onChange) { + onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, { + selectionDirty: false, + filters, + pagination, + }))); + } }); } @@ -463,7 +466,7 @@ export default class Table extends React.Component { .map((item, i) => this.getRecordKey(item, i)); // 记录变化的列 - const changeRowKeys = []; + const changeRowKeys: string[] = []; if (checked) { changableRowKeys.forEach(key => { if (selectedRowKeys.indexOf(key) < 0) { @@ -511,10 +514,13 @@ export default class Table extends React.Component { } this.setState(newState); - this.props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, { - selectionDirty: false, - pagination, - }))); + const onChange = this.props.onChange; + if (onChange) { + onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, { + selectionDirty: false, + pagination, + }))); + } } renderSelectionRadio = (_, record, index) => { @@ -558,7 +564,7 @@ export default class Table extends React.Component { ); } - getRecordKey(record, index?) { + getRecordKey(record, index?): string { const rowKey = this.props.rowKey; if (typeof rowKey === 'function') { return rowKey(record, index); @@ -584,11 +590,11 @@ export default class Table extends React.Component { } renderRowSelection() { - const prefixCls = this.props.prefixCls; + const { prefixCls, rowSelection } = this.props; const columns = this.props.columns.concat(); - if (this.props.rowSelection) { + if (rowSelection) { const data = this.getFlatCurrentPageData().filter((item) => { - if (this.props.rowSelection.getCheckboxProps) { + if (rowSelection.getCheckboxProps) { return !this.getCheckboxPropsByItem(item).disabled; } return true; @@ -617,7 +623,7 @@ export default class Table extends React.Component { ); } let selectionColumn; - if (this.props.rowSelection.type === 'radio') { + if (rowSelection.type === 'radio') { selectionColumn = { key: 'selection-column', render: this.renderSelectionRadio, @@ -689,7 +695,7 @@ export default class Table extends React.Component { selectedKeys={colFilters} confirmFilter={this.handleFilter} prefixCls={`${prefixCls}-filter`} - dropdownPrefixCls={dropdownPrefixCls} + dropdownPrefixCls={dropdownPrefixCls || 'ant-dropdown'} /> ); } @@ -736,9 +742,13 @@ export default class Table extends React.Component { pagination.onShowSizeChange(current, pageSize); const nextPagination = assign({}, pagination, { pageSize, current }); this.setState({ pagination: nextPagination }); - this.props.onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, { - pagination: nextPagination, - }))); + + const onChange = this.props.onChange; + if (onChange) { + onChange.apply(null, this.prepareParamsArguments(assign({}, this.state, { + pagination: nextPagination, + }))); + } } renderPagination() { @@ -819,7 +829,7 @@ export default class Table extends React.Component { } recursiveSort(data, sorterFn) { - const { childrenColumnName } = this.props; + const { childrenColumnName = 'children' } = this.props; return data.sort(sorterFn).map(item => (item[childrenColumnName] ? assign( {}, item, { @@ -849,8 +859,9 @@ export default class Table extends React.Component { if (values.length === 0) { return; } - data = col.onFilter ? data.filter(record => { - return values.some(v => col.onFilter(v, record)); + const onFilter = col.onFilter; + data = onFilter ? data.filter(record => { + return values.some(v => onFilter(v, record)); }) : data; }); } diff --git a/components/table/filterDropdown.tsx b/components/table/filterDropdown.tsx index 93242288bb..2b6813499b 100755 --- a/components/table/filterDropdown.tsx +++ b/components/table/filterDropdown.tsx @@ -4,15 +4,7 @@ import Dropdown from '../dropdown'; import Icon from '../icon'; import Checkbox from '../checkbox'; import Radio from '../radio'; - -export interface FilterDropdownMenuWrapperProps { - onClick?: React.MouseEventHandler; - children?: any; - className?: string; -} -const FilterDropdownMenuWrapper: React.StatelessComponent = - ({ onClick, children, className }) => -
{children}
; +import FilterDropdownMenuWrapper from './FilterDropdownMenuWrapper'; export interface FilterMenuProps { locale: any; diff --git a/components/table/util.tsx b/components/table/util.tsx index 245b935365..6c7b56e9e4 100644 --- a/components/table/util.tsx +++ b/components/table/util.tsx @@ -1,6 +1,6 @@ import assign from 'object-assign'; -export function flatArray(data = [], childrenName = 'children') { - const result = []; +export function flatArray(data: Object[] = [], childrenName = 'children') { + const result: Object[] = []; const loop = (array) => { array.forEach(item => { const newItem = assign({}, item); diff --git a/components/tabs/index.tsx b/components/tabs/index.tsx index 526e027255..cb47341b04 100755 --- a/components/tabs/index.tsx +++ b/components/tabs/index.tsx @@ -15,7 +15,7 @@ export interface TabsProps { hideAdd?: boolean; onChange?: (activeKey: string) => void; onTabClick?: Function; - tabBarExtraContent?: React.ReactNode; + tabBarExtraContent?: React.ReactNode | null; type?: TabsType; tabPosition?: TabsPosition; onEdit?: (targetKey: string, action: any) => void; @@ -24,6 +24,7 @@ export interface TabsProps { prefixCls?: string; className?: string; animated?: boolean; + children: any; } // Tabs @@ -38,15 +39,15 @@ export default class Tabs extends React.Component { static defaultProps = { prefixCls: 'ant-tabs', - type: 'line', // or 'card' 'editable-card' - onChange() { }, - onEdit() { }, hideAdd: false, animated: true, }; createNewTab = (targetKey) => { - this.props.onEdit(targetKey, 'add'); + const onEdit = this.props.onEdit; + if (onEdit) { + onEdit(targetKey, 'add'); + } } removeTab = (targetKey, e) => { @@ -54,18 +55,26 @@ export default class Tabs extends React.Component { if (!targetKey) { return; } - this.props.onEdit(targetKey, 'remove'); + + const onEdit = this.props.onEdit; + if (onEdit) { + onEdit(targetKey, 'remove'); + } } handleChange = (activeKey) => { - this.props.onChange(activeKey); + const onChange = this.props.onChange; + if (onChange) { + onChange(activeKey); + } } render() { let { prefixCls, + className = '', size, - type, + type = 'line', tabPosition, children, tabBarExtraContent, @@ -73,8 +82,8 @@ export default class Tabs extends React.Component { onTabClick, animated, } = this.props; - let className = classNames({ - [this.props.className]: !!this.props.className, + let cls = classNames({ + [className]: !!className, [`${prefixCls}-mini`]: size === 'small' || size as string === 'mini', [`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right', [`${prefixCls}-card`]: type.indexOf('card') >= 0, @@ -115,7 +124,7 @@ export default class Tabs extends React.Component { return ( ( { static defaultProps = { prefixCls: 'ant-tag', closable: false, - onClose() { }, - afterClose() { }, }; constructor(props) { @@ -36,7 +34,10 @@ export default class Tag extends React.Component { } close = (e) => { - this.props.onClose(e); + const onClose = this.props.onClose; + if (onClose) { + onClose(e); + } if (e.defaultPrevented) { return; } @@ -55,7 +56,11 @@ export default class Tag extends React.Component { closed: true, closing: false, }); - this.props.afterClose(); + + const afterClose = this.props.afterClose; + if (afterClose) { + afterClose(); + } } } diff --git a/components/time-picker/index.tsx b/components/time-picker/index.tsx index 5c524b08a7..7d5d5501de 100644 --- a/components/time-picker/index.tsx +++ b/components/time-picker/index.tsx @@ -42,10 +42,7 @@ export interface TimePickerContext { export default class TimePicker extends React.Component { static defaultProps = { - format: 'HH:mm:ss', prefixCls: 'ant-time-picker', - onChange() { - }, align: { offset: [0, -2], }, @@ -82,7 +79,10 @@ export default class TimePicker extends React.Component { if (!('value' in this.props)) { this.setState({ value }); } - this.props.onChange(value, (value && value.format(this.props.format)) || ''); + const { onChange, format = 'HH:mm:ss' } = this.props; + if (onChange) { + onChange(value, (value && value.format(format)) || ''); + } } getLocale() { diff --git a/components/tooltip/index.tsx b/components/tooltip/index.tsx index cc4e8b5837..6d06b572ae 100644 --- a/components/tooltip/index.tsx +++ b/components/tooltip/index.tsx @@ -41,7 +41,6 @@ export default class Tooltip extends React.Component { transitionName: 'zoom-big-fast', mouseEnterDelay: 0.1, mouseLeaveDelay: 0.1, - onVisibleChange() {}, arrowPointAtCenter: false, }; @@ -59,7 +58,10 @@ export default class Tooltip extends React.Component { onVisibleChange = (visible) => { this.setState({ visible }); - this.props.onVisibleChange(visible); + const onVisibleChange = this.props.onVisibleChange; + if (onVisibleChange) { + onVisibleChange(visible); + } } getPopupDomNode() { diff --git a/components/transfer/index.tsx b/components/transfer/index.tsx index 40e029cb25..8d238d9416 100644 --- a/components/transfer/index.tsx +++ b/components/transfer/index.tsx @@ -9,7 +9,7 @@ function noop() { } export interface TransferItem { - key: number | string; + key: string; title: string; description?: string; disabled?: boolean; @@ -50,15 +50,9 @@ export default class Transfer extends React.Component { static Search = Search; static defaultProps = { - prefixCls: 'ant-transfer', dataSource: [], render: noop, - onChange: noop, - onSelectChange: noop, - operations: [], showSearch: false, - body: noop, - footer: noop, }; static propTypes = { @@ -119,20 +113,20 @@ export default class Transfer extends React.Component { }); } } - splitDataSource(props) { + splitDataSource(props: TransferProps) { if (this.splitedDataSource) { return this.splitedDataSource; } - const { dataSource, targetKeys = [] } = props; - if (props.rowKey) { + const { rowKey, dataSource, targetKeys = [] } = props; + if (rowKey) { dataSource.forEach(record => { - record.key = props.rowKey(record); + record.key = rowKey(record); }); } const leftDataSource = dataSource.filter(({ key }) => targetKeys.indexOf(key) === -1); - const rightDataSource = []; + const rightDataSource: TransferItem[] = []; targetKeys.forEach((targetKey) => { const targetItem = dataSource.filter(record => record.key === targetKey)[0]; if (targetItem) { @@ -164,7 +158,9 @@ export default class Transfer extends React.Component { }); this.handleSelectChange(oppositeDirection, []); - onChange(newTargetKeys, direction, moveKeys); + if (onChange) { + onChange(newTargetKeys, direction, moveKeys); + } } moveToLeft = () => this.moveTo('left') @@ -173,6 +169,10 @@ export default class Transfer extends React.Component { handleSelectChange(direction: string, holder: string[]) { const { leftCheckedKeys, rightCheckedKeys } = this.state; const onSelectChange = this.props.onSelectChange; + if (!onSelectChange) { + return; + } + if (direction === 'left') { onSelectChange(holder, rightCheckedKeys); } else { @@ -253,8 +253,8 @@ export default class Transfer extends React.Component { render() { const { - prefixCls, operations, showSearch, notFoundContent, - searchPlaceholder, body, footer, listStyle, className, + prefixCls = 'ant-transfer', operations = [], showSearch, notFoundContent, + searchPlaceholder, body, footer, listStyle, className = '', filterOption, render, } = this.props; const { leftFilter, rightFilter, leftCheckedKeys, rightCheckedKeys } = this.state; diff --git a/components/transfer/list.tsx b/components/transfer/list.tsx index da2fd449c9..b2e9792b1f 100644 --- a/components/transfer/list.tsx +++ b/components/transfer/list.tsx @@ -17,21 +17,21 @@ export function isRenderResultPlainObject(result) { } export interface TransferListProps { - prefixCls?: string; + prefixCls: string; dataSource: TransferItem[]; filter?: string; showSearch?: boolean; searchPlaceholder?: string; titleText?: string; style?: React.CSSProperties; - handleFilter?: (e: any) => void; - handleSelect?: (selectedItem: any, checked: boolean) => void; - handleSelectAll?: (dataSource: any[], checkAll: boolean) => void; - handleClear?: () => void; + handleFilter: (e: any) => void; + handleSelect: (selectedItem: any, checked: boolean) => void; + handleSelectAll: (dataSource: any[], checkAll: boolean) => void; + handleClear: () => void; render?: (item: any) => any; body?: (props: any) => any; footer?: (props: any) => void; - checkedKeys?: any[]; + checkedKeys: string[]; checkStatus?: boolean; position?: string; notFoundContent?: React.ReactNode | string; @@ -49,14 +49,7 @@ export default class TransferList extends React.Component { const renderResult = render(item); @@ -207,7 +200,7 @@ export default class TransferList extends React.Component this.handleSelect(item)} + onClick={item.disabled ? undefined : () => this.handleSelect(item)} > key === item.key)} disabled={item.disabled} /> {renderedEl} diff --git a/components/transfer/search.tsx b/components/transfer/search.tsx index ba69224290..35237df511 100644 --- a/components/transfer/search.tsx +++ b/components/transfer/search.tsx @@ -2,9 +2,6 @@ import React from 'react'; import Icon from '../icon'; import Input from '../input'; -function noop() { -} - export interface SearchProps { prefixCls?: string; placeholder?: string; @@ -16,17 +13,22 @@ export interface SearchProps { export default class Search extends React.Component { static defaultProps = { placeholder: '', - onChange: noop, - handleClear: noop, }; handleChange = (e) => { - this.props.onChange(e); + const onChange = this.props.onChange; + if (onChange) { + onChange(e); + } } handleClear = (e) => { e.preventDefault(); - this.props.handleClear(e); + + const handleClear = this.props.handleClear; + if (handleClear) { + handleClear(e); + } } render() { diff --git a/components/tree-select/index.tsx b/components/tree-select/index.tsx index daabb135c5..229b6b4e04 100644 --- a/components/tree-select/index.tsx +++ b/components/tree-select/index.tsx @@ -28,7 +28,7 @@ export default class TreeSelect extends React.Component { render() { const props = this.props; let { - size, className, notFoundContent, prefixCls, + size, className = '', notFoundContent, prefixCls, } = this.props; const cls = classNames({ diff --git a/components/upload/index.tsx b/components/upload/index.tsx index d0b2ed53ff..633a412dca 100644 --- a/components/upload/index.tsx +++ b/components/upload/index.tsx @@ -6,16 +6,13 @@ import classNames from 'classnames'; import assign from 'object-assign'; import { UploadProps } from './interface'; -function noop() { -} - function T() { return true; } // Fix IE file.status problem // via coping a new Object -function fileToObject(file) { +function fileToObject(file): any { return { lastModified: file.lastModified, lastModifiedDate: file.lastModifiedDate, @@ -64,20 +61,16 @@ export default class Upload extends React.Component { static Dragger = Dragger; static defaultProps = { - prefixCls: 'ant-upload', type: 'select', multiple: false, action: '', data: {}, accept: '', - onChange: noop, beforeUpload: T, showUploadList: true, listType: 'text', // or pictrue className: '', disabled: false, - onRemove() {}, - onPreview() {}, }; recentUploadStatus: boolean | PromiseLike; @@ -194,7 +187,10 @@ export default class Upload extends React.Component { } handleRemove(file) { - this.props.onRemove(file); + const onRemove = this.props.onRemove; + if (onRemove) { + onRemove(file); + } let fileList = this.removeFile(file); if (fileList) { this.onChange({ @@ -214,7 +210,11 @@ export default class Upload extends React.Component { if (!('fileList' in this.props)) { this.setState({ fileList: info.fileList }); } - this.props.onChange(info); + + const onChange = this.props.onChange; + if (onChange) { + onChange(info); + } } componentWillReceiveProps(nextProps) { @@ -237,7 +237,7 @@ export default class Upload extends React.Component { render() { const { - prefixCls, showUploadList, listType, onPreview, + prefixCls = 'ant-upload', showUploadList, listType, onPreview, type, disabled, children, className, } = this.props; diff --git a/components/upload/uploadList.tsx b/components/upload/uploadList.tsx index f8cfbeb725..fcaee44211 100644 --- a/components/upload/uploadList.tsx +++ b/components/upload/uploadList.tsx @@ -15,7 +15,6 @@ const previewFile = (file, callback) => { export default class UploadList extends React.Component { static defaultProps = { listType: 'text', // or picture - items: [], progressAttr: { strokeWidth: 3, showInfo: false, @@ -24,19 +23,27 @@ export default class UploadList extends React.Component { }; handleClose = (file) => { - this.props.onRemove(file); + const onRemove = this.props.onRemove; + if (onRemove) { + onRemove(file); + } } handlePreview = (file, e) => { e.preventDefault(); - return this.props.onPreview(file); + const onPreview = this.props.onPreview; + if (!onPreview) { + return; + } + + return onPreview(file); } componentDidUpdate() { if (this.props.listType !== 'picture' && this.props.listType !== 'picture-card') { return; } - this.props.items.forEach(file => { + (this.props.items || []).forEach(file => { if (typeof document === 'undefined' || typeof window === 'undefined' || !(window as any).FileReader || !(window as any).File || @@ -57,7 +64,7 @@ export default class UploadList extends React.Component { } render() { - const { prefixCls, items, listType } = this.props; + const { prefixCls, items = [], listType } = this.props; const list = items.map(file => { let progress; let icon = ; diff --git a/tsconfig.json b/tsconfig.json index 36444138b3..4427691e68 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "strictNullChecks": false, + "strictNullChecks": true, "moduleResolution": "node", "allowSyntheticDefaultImports": true, "jsx": "preserve",