feat: tsconfig enable strict (#47998)

* feat: tsconfig enable strict

* feat: add no-explicit-any

* feat: strict

* feat: as THEME

* feat: 优化 keys 类型写法

* feat: demo remove any

* feat: as number

* feat: this any

* feat: add eslint

* feat: cascader

* feat: props any

* feat: remove any

* feat: remove any

* feat: any 提示错误

* feat: remove any

* feat: add eslint

* feat: 允许 T = any 存在

* feat: color funciton

* feat: 恢复 lint

* feat: merge master

* feat: as ReactElement

* feat: type
This commit is contained in:
叶枫 2024-04-01 15:49:45 +08:00 committed by GitHub
parent 4eaa664d2e
commit 14a1e6bd51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
136 changed files with 505 additions and 433 deletions

View File

@ -85,7 +85,7 @@ const ThemePicker: React.FC<ThemePickerProps> = (props) => {
const [locale] = useLocale(locales);
return (
<Flex gap="large" wrap="wrap">
{Object.keys(THEMES).map<React.ReactNode>((theme: THEME, index) => (
{(Object.keys(THEMES) as (keyof typeof THEMES)[]).map<React.ReactNode>((theme, index) => (
<Flex vertical gap="small" justify="center" align="center" key={theme}>
<label
onClick={() => onChange?.(theme)}

View File

@ -45,7 +45,7 @@ const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
if (typeof ResizeObserver !== 'undefined') {
const resizeObserver = new ResizeObserver((entries) => {
const element: HTMLDivElement = entries[0].target as any;
const element = entries[0].target as HTMLDivElement;
setPopupHeight(element.offsetHeight + 8);
setPopupWidth(element.offsetWidth);
});

View File

@ -95,16 +95,16 @@ export default function useResponsiveObserver() {
if (!subscribers.size) this.unregister();
},
unregister() {
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
const matchMediaQuery = responsiveMap[screen];
Object.keys(responsiveMap).forEach((screen) => {
const matchMediaQuery = responsiveMap[screen as Breakpoint];
const handler = this.matchHandlers[matchMediaQuery];
handler?.mql.removeListener(handler?.listener);
});
subscribers.clear();
},
register() {
Object.keys(responsiveMap).forEach((screen: Breakpoint) => {
const matchMediaQuery = responsiveMap[screen];
Object.keys(responsiveMap).forEach((screen) => {
const matchMediaQuery = responsiveMap[screen as Breakpoint];
const listener = ({ matches }: { matches: boolean }) => {
this.dispatch({
...screens,

View File

@ -23,7 +23,7 @@ const AffixMounter: React.FC<AffixProps> = (props) => {
container.current.addEventListener = jest
.fn()
.mockImplementation((event: keyof HTMLElementEventMap, cb: (ev: Event) => void) => {
events[event] = cb;
(events as any)[event] = cb;
});
}
}, []);
@ -37,8 +37,8 @@ const AffixMounter: React.FC<AffixProps> = (props) => {
};
describe('Affix Render', () => {
rtlTest(Affix);
accessibilityTest(Affix);
rtlTest(Affix as any);
accessibilityTest(Affix as any);
const domMock = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect');

View File

@ -1,5 +1,6 @@
import { spyElementPrototype } from 'rc-util/lib/test/domHook';
import * as React from 'react';
import { spyElementPrototype } from 'rc-util/lib/test/domHook';
import demoTest, { rootPropsTest } from '../../../tests/shared/demoTest';
demoTest('affix', {
@ -16,10 +17,11 @@ rootPropsTest(
{
beforeRender: () => {
spyElementPrototype(HTMLElement, 'getBoundingClientRect', function getBoundingClientRect() {
// @ts-ignore
if (this.id === 'holder') {
return { top: 0, bottom: 100 };
}
// @ts-ignore
if (this.className === 'fixed') {
return { top: -100, bottom: -100 };
}

View File

@ -334,7 +334,7 @@ describe('Calendar', () => {
const onTypeChange = jest.fn();
const value = Dayjs('2018-12-03');
const wrapper = render(
<Header
<Header<Dayjs.Dayjs>
prefixCls="ant-picker-calendar"
generateConfig={dayjsGenerateConfig}
onModeChange={onTypeChange}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import type { BasePickerPanelProps as RcBasePickerPanelProps } from 'rc-picker';
import { PickerPanel as RCPickerPanel } from 'rc-picker';
import type { GenerateConfig } from 'rc-picker/lib/generate';
import type { CellRenderInfo } from 'rc-picker/lib/interface';
@ -246,7 +247,7 @@ function generateCalendar<DateType extends AnyObject>(generateConfig: GenerateCo
const [contextLocale] = useLocale('Calendar', getDefaultLocale);
const mergedCellRender = (current: DateType, info: CellRenderInfo<DateType>) => {
const mergedCellRender: RcBasePickerPanelProps['cellRender'] = (current, info) => {
if (info.type === 'date') {
return dateRender(current, info);
}

View File

@ -147,7 +147,7 @@ const Card = React.forwardRef<HTMLDivElement, CardProps>((props, ref) => {
const isContainGrid = React.useMemo<boolean>(() => {
let containGrid = false;
React.Children.forEach(children, (element: JSX.Element) => {
React.Children.forEach(children as React.ReactElement, (element: JSX.Element) => {
if (element && element.type && element.type === Grid) {
containGrid = true;
}

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -57,7 +57,7 @@ const handleAreaClick = (
console.log('clicked', label, option);
};
const displayRender = (labels: string[], selectedOptions: DefaultOptionType[]) =>
const displayRender: CascaderProps<Option>['displayRender'] = (labels, selectedOptions = []) =>
labels.map((label, i) => {
const option = selectedOptions[i];
if (i === labels.length - 1) {

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -33,7 +34,7 @@ const options: Option[] = [
const App: React.FC = () => {
const [text, setText] = useState('Unselect');
const onChange = (_: string[], selectedOptions: Option[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (_, selectedOptions) => {
setText(selectedOptions.map((o) => o.label).join(', '));
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -44,7 +45,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
code: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { MultipleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string | number;
@ -43,7 +44,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[][]) => {
const onChange: MultipleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader, Flex } from 'antd';
import type { MultipleCascaderProps, SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string | number;
@ -42,14 +43,18 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};
const onMultipleChange: MultipleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};
const App: React.FC = () => (
<Flex vertical gap="small" align="flex-start">
<Cascader.Panel options={options} onChange={onChange} />
<Cascader.Panel multiple options={options} onChange={onChange} />
<Cascader.Panel multiple options={options} onChange={onMultipleChange} />
<Cascader.Panel />
</Flex>
);

View File

@ -1,6 +1,7 @@
import React from 'react';
import { Cascader } from 'antd';
import type { GetProp, CascaderProps } from 'antd';
import type { CascaderProps, GetProp } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
type DefaultOptionType = GetProp<CascaderProps, 'options'>[number];
@ -51,7 +52,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[], selectedOptions: Option[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value, selectedOptions) => {
console.log(value, selectedOptions);
};

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { MultipleCascaderProps } from 'antd/es/cascader';
const { SHOW_CHILD } = Cascader;
@ -43,7 +44,7 @@ const options: Option[] = [
];
const App: React.FC = () => {
const onChange = (value: string[][]) => {
const onChange: MultipleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};
return (

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -42,7 +43,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -1,6 +1,7 @@
import React from 'react';
import { SmileOutlined } from '@ant-design/icons';
import { Cascader } from 'antd';
import type { SingleCascaderProps } from 'antd/es/cascader';
interface Option {
value: string;
@ -43,7 +44,7 @@ const options: Option[] = [
},
];
const onChange = (value: string[]) => {
const onChange: SingleCascaderProps<Option>['onChange'] = (value) => {
console.log(value);
};

View File

@ -56,7 +56,10 @@ function highlightKeyword(str: string, lowerKeyword: string, prefixCls?: string)
const cells = str
.toLowerCase()
.split(lowerKeyword)
.reduce((list, cur, index) => (index === 0 ? [cur] : [...list, lowerKeyword, cur]), []);
.reduce<string[]>(
(list, cur, index) => (index === 0 ? [cur] : [...list, lowerKeyword, cur]),
[],
);
const fillCells: React.ReactNode[] = [];
let start = 0;
@ -102,13 +105,13 @@ const defaultSearchRender: ShowSearchType['render'] = (inputValue, path, prefixC
return optionList;
};
type SingleCascaderProps<OptionType extends BaseOptionType> = Omit<
export type SingleCascaderProps<OptionType extends BaseOptionType = any> = Omit<
RcSingleCascaderProps<OptionType>,
'checkable' | 'options'
> & {
multiple?: false;
};
type MultipleCascaderProps<OptionType extends BaseOptionType> = Omit<
export type MultipleCascaderProps<OptionType extends BaseOptionType = any> = Omit<
RcMultipleCascaderProps<OptionType>,
'checkable' | 'options'
> & {

View File

@ -154,6 +154,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction<CheckboxRef, CheckboxProp
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{/* @ts-ignore */}
<RcCheckbox
aria-checked={ariaChecked}
{...checkboxProps}

View File

@ -6,6 +6,7 @@ import { ConfigContext } from '../config-provider';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import type { CheckboxChangeEvent } from './Checkbox';
import Checkbox from './Checkbox';
import type { CheckboxGroupContext } from './GroupContext';
import GroupContext from './GroupContext';
import useStyle from './style';
@ -69,7 +70,7 @@ const CheckboxGroup = React.forwardRef(
const memoOptions = React.useMemo<CheckboxOptionType<T>[]>(
() =>
options.map<CheckboxOptionType<T>>((option: CheckboxOptionType<T>) => {
options.map<CheckboxOptionType<T>>((option: any) => {
if (typeof option === 'string' || typeof option === 'number') {
return { label: option, value: option };
}
@ -82,11 +83,11 @@ const CheckboxGroup = React.forwardRef(
setRegisteredValues((prevValues) => prevValues.filter((v) => v !== val));
};
const registerValue = (val: T) => {
const registerValue: CheckboxGroupContext<T>['registerValue'] = (val) => {
setRegisteredValues((prevValues) => [...prevValues, val]);
};
const toggleOption = (option: CheckboxOptionType<T>) => {
const toggleOption: CheckboxGroupContext<T>['toggleOption'] = (option) => {
const optionIndex = value.indexOf(option.value);
const newValue = [...value];
if (optionIndex === -1) {
@ -136,8 +137,7 @@ const CheckboxGroup = React.forwardRef(
))
: children;
// eslint-disable-next-line react/jsx-no-constructed-context-values
const context = {
const context: CheckboxGroupContext<any> = {
toggleOption,
value,
disabled: restProps.disabled,

View File

@ -1,9 +1,10 @@
import React from 'react';
import type { CheckboxOptionType, CheckboxValueType } from './Group';
export interface CheckboxGroupContext<T extends CheckboxValueType = CheckboxValueType> {
name?: string;
toggleOption?: (option: CheckboxOptionType) => void;
toggleOption?: (option: CheckboxOptionType<T>) => void;
value?: any;
disabled?: boolean;
registerValue: (val: T) => void;

View File

@ -155,6 +155,7 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
);
return wrapCSSVar(
// @ts-ignore
<RcCollapse
ref={ref}
openMotion={openMotion}

View File

@ -1,9 +1,8 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import { resetWarned } from '../../_util/warning';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
describe('Collapse', () => {
// eslint-disable-next-line global-require
@ -160,7 +159,7 @@ describe('Collapse', () => {
.spyOn(window, 'requestAnimationFrame')
.mockImplementation((cb) => setTimeout(cb, 16.66));
let setActiveKeyOuter: React.Dispatch<React.SetStateAction<React.Key>>;
let setActiveKeyOuter: React.Dispatch<React.SetStateAction<React.Key | undefined>>;
const Test: React.FC = () => {
const [activeKey, setActiveKey] = React.useState<React.Key>();
setActiveKeyOuter = setActiveKey;

View File

@ -1,5 +1,4 @@
import React, { useContext, useMemo, useRef } from 'react';
import type { HsbaColorType } from '@rc-component/color-picker';
import classNames from 'classnames';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
@ -15,6 +14,7 @@ import { FormItemInputContext, NoFormStyle } from '../form/context';
import type { PopoverProps } from '../popover';
import Popover from '../popover';
import type { Color } from './color';
import type { ColorPickerPanelProps } from './ColorPickerPanel';
import ColorPickerPanel from './ColorPickerPanel';
import ColorTrigger from './components/ColorTrigger';
import useColorState from './hooks/useColorState';
@ -118,8 +118,8 @@ const ColorPicker: CompoundedComponent = (props) => {
);
}
const handleChange = (data: Color, type?: HsbaColorType, pickColor?: boolean) => {
let color: Color = generateColor(data);
const handleChange: ColorPickerPanelProps['onChange'] = (data, type, pickColor) => {
let color: Color = generateColor(data as Color);
// If color is cleared, reset alpha to 100
const isNull = value === null || (!value && defaultValue === null);

View File

@ -1,6 +1,7 @@
import type { HsbaColorType } from '@rc-component/color-picker';
import type { FC } from 'react';
import React from 'react';
import type { HsbaColorType } from '@rc-component/color-picker';
import Divider from '../divider';
import type { Color } from './color';
import PanelPicker from './components/PanelPicker';
@ -8,7 +9,7 @@ import PanelPresets from './components/PanelPresets';
import { PanelPickerProvider, PanelPresetsProvider } from './context';
import type { ColorPickerBaseProps } from './interface';
interface ColorPickerPanelProps extends ColorPickerBaseProps {
export interface ColorPickerPanelProps extends ColorPickerBaseProps {
onChange?: (value?: Color, type?: HsbaColorType, pickColor?: boolean) => void;
onClear?: () => void;
}

View File

@ -1,5 +1,6 @@
import type { FC } from 'react';
import React, { useEffect, useState } from 'react';
import type { Color } from '../color';
import type { ColorPickerBaseProps } from '../interface';
import { generateColor, getAlphaColor } from '../util';
@ -21,7 +22,7 @@ const ColorAlphaInput: FC<ColorAlphaInputProps> = ({ prefixCls, value, onChange
}
}, [value]);
const handleAlphaChange = (step: number) => {
const handleAlphaChange = (step: number | null) => {
const hsba = alphaValue.toHsb();
hsba.a = (step || 0) / 100;
const genColor = generateColor(hsba);

View File

@ -1,9 +1,10 @@
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import type { FC } from 'react';
import React, { useMemo } from 'react';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import Select from '../../select';
import type { Color } from '../color';
import type { ColorPickerBaseProps } from '../interface';
import type { ColorFormatType, ColorPickerBaseProps } from '../interface';
import { ColorFormat } from '../interface';
import ColorAlphaInput from './ColorAlphaInput';
import ColorHexInput from './ColorHexInput';
@ -30,7 +31,7 @@ const ColorInput: FC<ColorInputProps> = (props) => {
const colorInputPrefixCls = `${prefixCls}-input`;
const handleFormatChange = (newFormat: ColorFormat) => {
const handleFormatChange = (newFormat: ColorFormatType) => {
setColorFormat(newFormat);
};

View File

@ -65,7 +65,7 @@ const ColorPresets: FC<ColorPresetsProps> = ({ prefixCls, presets, value: color,
children: (
<div className={`${colorPresetsPrefixCls}-items`}>
{Array.isArray(preset?.colors) && preset.colors?.length > 0 ? (
preset.colors.map((presetColor: Color, index: number) => (
(preset.colors as Color[]).map((presetColor, index) => (
<ColorBlock
// eslint-disable-next-line react/no-array-index-key
key={`preset-${index}-${presetColor.toHexString()}`}

View File

@ -7,7 +7,7 @@ type Format = GetProp<ColorPickerProps, 'format'>;
const HexCase: React.FC = () => {
const [colorHex, setColorHex] = useState<Color>('#1677ff');
const [formatHex, setFormatHex] = useState<Format>('hex');
const [formatHex, setFormatHex] = useState<Format | undefined>('hex');
const hexString = React.useMemo<string>(
() => (typeof colorHex === 'string' ? colorHex : colorHex?.toHexString()),

View File

@ -28,7 +28,7 @@ const useColorState = (
return color;
});
const setColorValue: typeof _setColorValue = (color: Color) => {
const setColorValue = (color: Color) => {
_setColorValue(color);
prevColor.current = color;
};

View File

@ -1,8 +1,9 @@
import type { CSSProperties, FC, ReactNode } from 'react';
import type { Color } from './color';
import type { ColorPickerProps as RcColorPickerProps } from '@rc-component/color-picker';
import type { SizeType } from '../config-provider/SizeContext';
import type { PopoverProps } from '../popover';
import type { Color } from './color';
export enum ColorFormat {
hex = 'hex',
@ -10,6 +11,8 @@ export enum ColorFormat {
hsb = 'hsb',
}
export type ColorFormatType = keyof typeof ColorFormat;
export interface PresetsItem {
label: ReactNode;
colors: (string | Color)[];
@ -32,7 +35,7 @@ export type TriggerPlacement =
export interface ColorPickerBaseProps {
color?: Color;
prefixCls: string;
format?: keyof typeof ColorFormat;
format?: ColorFormatType;
allowClear?: boolean;
disabled?: boolean;
disabledAlpha?: boolean;
@ -55,8 +58,8 @@ export type ColorPickerProps = Omit<
disabled?: boolean;
placement?: TriggerPlacement;
trigger?: TriggerType;
format?: keyof typeof ColorFormat;
defaultFormat?: keyof typeof ColorFormat;
format?: ColorFormatType;
defaultFormat?: ColorFormatType;
allowClear?: boolean;
presets?: PresetsItem[];
arrow?: boolean | { pointAtCenter: boolean };
@ -71,7 +74,7 @@ export type ColorPickerProps = Omit<
disabledAlpha?: boolean;
[key: `data-${string}`]: string;
onOpenChange?: (open: boolean) => void;
onFormatChange?: (format: ColorFormat) => void;
onFormatChange?: (format?: ColorFormatType) => void;
onChange?: (value: Color, hex: string) => void;
onClear?: () => void;
onChangeComplete?: (value: Color) => void;

View File

@ -1,10 +1,11 @@
import useMemo from 'rc-util/lib/hooks/useMemo';
import isEqual from 'rc-util/lib/isEqual';
import type { OverrideToken } from '../../theme/interface';
import type { ThemeConfig } from '../context';
import { defaultConfig } from '../../theme/internal';
import useThemeKey from './useThemeKey';
import { devUseWarning } from '../../_util/warning';
import type { OverrideToken } from '../../theme/interface';
import { defaultConfig } from '../../theme/internal';
import type { ThemeConfig } from '../context';
import useThemeKey from './useThemeKey';
export default function useTheme(
theme?: ThemeConfig,
@ -51,7 +52,7 @@ export default function useTheme(
...parentThemeConfig.components,
};
Object.keys(theme.components || {}).forEach((componentName: keyof OverrideToken) => {
(Object.keys(theme.components || {}) as (keyof OverrideToken)[]).forEach((componentName) => {
mergedComponents[componentName] = {
...mergedComponents[componentName],
...theme.components![componentName],

View File

@ -467,7 +467,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
...parentContext,
};
Object.keys(baseConfig).forEach((key: keyof typeof baseConfig) => {
(Object.keys(baseConfig) as (keyof typeof baseConfig)[]).forEach((key) => {
if (baseConfig[key] !== undefined) {
(config as any)[key] = baseConfig[key];
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import type { DatePickerProps } from 'antd';
import { DatePicker, Space, theme } from 'antd';
import type { Dayjs } from 'dayjs';
import type { CellRenderInfo } from 'rc-picker/es/interface';
const App: React.FC = () => {
const { token } = theme.useToken();
@ -9,11 +9,11 @@ const App: React.FC = () => {
border: `1px solid ${token.colorPrimary}`,
borderRadius: '50%',
};
const cellRender = React.useCallback((current: number | Dayjs, info: CellRenderInfo<Dayjs>) => {
const cellRender: DatePickerProps<Dayjs>['cellRender'] = (current, info) => {
if (info.type !== 'date') {
return info.originNode;
}
if (typeof current === 'number') {
if (typeof current === 'number' || typeof current === 'string') {
return <div className="ant-picker-cell-inner">{current}</div>;
}
return (
@ -21,7 +21,7 @@ const App: React.FC = () => {
{current.date()}
</div>
);
}, []);
};
return (
<Space size={12} direction="vertical">
<DatePicker cellRender={cellRender} />

View File

@ -6,25 +6,27 @@ type RangePickerProps = GetProps<typeof DatePicker.RangePicker>;
const { RangePicker } = DatePicker;
const onChange = (
value: DatePickerProps['value'] | RangePickerProps['value'],
dateString: [string, string] | string,
) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
};
const onOk = (value: DatePickerProps['value'] | RangePickerProps['value']) => {
console.log('onOk: ', value);
};
const App: React.FC = () => (
<Space direction="vertical" size={12}>
<DatePicker showTime onChange={onChange} onOk={onOk} />
<DatePicker
showTime
onChange={(value, dateString) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
}}
onOk={onOk}
/>
<RangePicker
showTime={{ format: 'HH:mm' }}
format="YYYY-MM-DD HH:mm"
onChange={onChange}
onChange={(value, dateString) => {
console.log('Selected Time: ', value);
console.log('Formatted Selected Time: ', dateString);
}}
onOk={onOk}
/>
</Space>

View File

@ -113,7 +113,7 @@ export default function generateRangePicker<DateType extends AnyObject>(
</span>
}
disabled={mergedDisabled}
ref={innerRef}
ref={innerRef as any} // Need to modify PickerRef
popupAlign={transPlacement2DropdownAlign(direction, placement)}
placeholder={getRangePlaceholder(locale, picker, placeholder)}
suffixIcon={suffixNode}

View File

@ -65,9 +65,9 @@ const genMotionStyle: GenerateStyle<DrawerToken> = (token) => {
// ======================= Panel ========================
[`${componentCls}-panel-motion`]: ['left', 'right', 'top', 'bottom'].reduce(
(obj, direction: Direction) => ({
(obj, direction) => ({
...obj,
[`&-${direction}`]: getPanelMotionStyles(direction, motionDurationSlow),
[`&-${direction}`]: getPanelMotionStyles(direction as Direction, motionDurationSlow),
}),
{},
),

View File

@ -1,4 +1,5 @@
import React from 'react';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { render, waitFakeTimer } from '../../../tests/utils';
@ -16,8 +17,8 @@ jest.mock('../dropdown', () => {
Button: typeof ActualDropdownComponent.Button;
} = (props) => {
const clone: Record<string, any> = {};
Object.keys(props).forEach((key: keyof typeof props) => {
clone[key] = props[key];
Object.keys(props).forEach((key) => {
clone[key] = props[key as keyof typeof props];
});
dropdownProps = clone;
@ -58,7 +59,7 @@ describe('DropdownButton', () => {
const { rerender } = render(<DropdownButton {...props} />);
Object.keys(props).forEach((key: keyof DropdownProps) => {
(Object.keys(props) as (keyof DropdownProps)[]).forEach((key) => {
expect(dropdownProps[key]).toBe(props[key]);
});

View File

@ -20,6 +20,7 @@ import useFrameState from '../hooks/useFrameState';
import useItemRef from '../hooks/useItemRef';
import useStyle from '../style';
import { getFieldId, toArray } from '../util';
import type { ItemHolderProps } from './ItemHolder';
import ItemHolder from './ItemHolder';
import StatusProvider from './StatusProvider';
@ -199,7 +200,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
};
// >>>>> Collect noStyle Field error to the top FormItem
const onSubItemMetaChange = (subMeta: Meta & { destroy: boolean }, uniqueKeys: React.Key[]) => {
const onSubItemMetaChange: ItemHolderProps['onSubItemMetaChange'] = (subMeta, uniqueKeys) => {
// Only `noStyle` sub item will trigger
setSubFieldErrors((prevSubFieldErrors) => {
const clone = {
@ -210,7 +211,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
const mergedNamePath = [...subMeta.name.slice(0, -1), ...uniqueKeys];
const mergedNameKey = mergedNamePath.join(NAME_SPLIT);
if (subMeta.destroy) {
if ((subMeta as any).destroy) {
// Remove
delete clone[mergedNameKey];
} else {
@ -301,7 +302,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
validateTrigger={mergedValidateTrigger}
onMetaChange={onMetaChange}
>
{(control, renderMeta, context: FormInstance<Values>) => {
{(control, renderMeta, context) => {
const mergedName = toArray(name).length && renderMeta ? renderMeta.name : [];
const fieldId = getFieldId(mergedName, formName);
@ -423,7 +424,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
</MemoInput>
);
} else if (isRenderProps && (shouldUpdate || dependencies) && !hasName) {
childNode = mergedChildren(context);
childNode = mergedChildren(context as any);
} else {
warning(
!mergedName.length,

View File

@ -1,4 +1,5 @@
import React, { useState } from 'react';
import type { InputNumberProps } from 'antd';
import { Form, InputNumber } from 'antd';
type ValidateStatus = Parameters<typeof Form.Item>[0]['validateStatus'];
@ -36,10 +37,10 @@ const App: React.FC = () => {
errorMsg?: string | null;
}>({ value: 11 });
const onNumberChange = (value: number) => {
const onNumberChange: InputNumberProps['onChange'] = (value) => {
setNumber({
...validatePrimeNumber(value),
value,
...validatePrimeNumber(value as number),
value: value as number,
});
};

View File

@ -43,7 +43,7 @@ const App: React.FC = () => {
onChange={setGutterKey}
marks={gutters}
step={null}
tooltip={{ formatter: (value: number) => gutters[value] }}
tooltip={{ formatter: (value) => gutters[value as number] }}
/>
</div>
<span>Vertical Gutter (px): </span>
@ -55,7 +55,7 @@ const App: React.FC = () => {
onChange={setVgutterKey}
marks={vgutters}
step={null}
tooltip={{ formatter: (value: number) => vgutters[value] }}
tooltip={{ formatter: (value) => vgutters[value as number] }}
/>
</div>
<span>Column Count:</span>
@ -67,7 +67,7 @@ const App: React.FC = () => {
onChange={setColCountKey}
marks={colCounts}
step={null}
tooltip={{ formatter: (value: number) => colCounts[value] }}
tooltip={{ formatter: (value) => colCounts[value as number] }}
/>
</div>
<Row gutter={[gutters[gutterKey], vgutters[vgutterKey]]}>

View File

@ -198,7 +198,7 @@ export const useColStyle = genStyleHooks(
genGridStyle(gridToken, ''),
genGridStyle(gridToken, '-xs'),
Object.keys(gridMediaSizesMap)
.map((key: GridMediaSize) => genGridMediaStyle(gridToken, gridMediaSizesMap[key], key))
.map((key) => genGridMediaStyle(gridToken, gridMediaSizesMap[key as GridMediaSize], key))
.reduce((pre, cur) => ({ ...pre, ...cur }), {}),
];
},

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';
const onChange = (value: number) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';
const onChange = (value: number) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber } from 'antd';
const onChange = (value: string) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,24 +1,25 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber, Space } from 'antd';
const onChange = (value: number | string) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};
const App: React.FC = () => (
<Space>
<InputNumber
<InputNumber<number>
defaultValue={1000}
formatter={(value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
parser={(value) => value!.replace(/\$\s?|(,*)/g, '')}
parser={(value) => value?.replace(/\$\s?|(,*)/g, '') as unknown as number}
onChange={onChange}
/>
<InputNumber
<InputNumber<number>
defaultValue={100}
min={0}
max={100}
formatter={(value) => `${value}%`}
parser={(value) => value!.replace('%', '')}
parser={(value) => value?.replace('%', '') as unknown as number}
onChange={onChange}
/>
</Space>

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { InputNumberProps } from 'antd';
import { InputNumber, Space } from 'antd';
const onChange = (value: number) => {
const onChange: InputNumberProps['onChange'] = (value) => {
console.log('changed', value);
};

View File

@ -1,4 +1,3 @@
import classNames from 'classnames';
import type {
CSSProperties,
FC,
@ -9,6 +8,8 @@ import type {
ReactNode,
} from 'react';
import React, { Children, forwardRef, useContext } from 'react';
import classNames from 'classnames';
import { cloneElement } from '../_util/reactNode';
import { ConfigContext } from '../config-provider';
import { Col } from '../grid';
@ -76,7 +77,7 @@ const InternalItem: ForwardRefRenderFunction<HTMLDivElement, ListItemProps> = (
const isItemContainsTextNodeAndNotSingular = () => {
let result;
Children.forEach(children, (element: ReactElement<any>) => {
Children.forEach(children as ReactElement, (element) => {
if (typeof element === 'string') {
result = true;
}

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { Mentions } from 'antd';
import type { MentionsProps } from 'rc-mentions';
const MOCK_DATA = {
'@': ['afc163', 'zombiej', 'yesmeck'],
@ -11,8 +12,8 @@ type PrefixType = keyof typeof MOCK_DATA;
const App: React.FC = () => {
const [prefix, setPrefix] = useState<PrefixType>('@');
const onSearch = (_: string, newPrefix: PrefixType) => {
setPrefix(newPrefix);
const onSearch: MentionsProps['onSearch'] = (_, newPrefix) => {
setPrefix(newPrefix as PrefixType);
};
return (

View File

@ -48,7 +48,7 @@ type Task =
| TypeTask
| {
type: 'destroy';
key: React.Key;
key?: React.Key;
skipped?: boolean;
};
@ -83,8 +83,8 @@ const GlobalHolder = React.forwardRef<
React.useImperativeHandle(ref, () => {
const instance: MessageInstance = { ...api };
Object.keys(instance).forEach((method: keyof MessageInstance) => {
instance[method] = (...args: any[]) => {
Object.keys(instance).forEach((method) => {
instance[method as keyof MessageInstance] = (...args: any[]) => {
sync();
return (api as any)[method](...args);
};
@ -286,13 +286,13 @@ function typeOpen(type: NoticeType, args: Parameters<TypeOpen>): MessageType {
return result;
}
function destroy(key: React.Key) {
const destroy: BaseMethods['destroy'] = (key) => {
taskQueue.push({
type: 'destroy',
key,
});
flushNotice();
}
};
interface BaseMethods {
open: (config: ArgsProps) => MessageType;

View File

@ -136,7 +136,7 @@ const Modal: React.FC<ModalProps> = (props) => {
footer={dialogFooter}
visible={open ?? visible}
mousePosition={restProps.mousePosition ?? mousePosition}
onClose={handleCancel}
onClose={handleCancel as any}
closable={mergedClosable}
closeIcon={mergedCloseIcon}
focusTriggerAfterClose={focusTriggerAfterClose}

View File

@ -121,7 +121,7 @@ export default function confirm(config: ModalFuncProps) {
if (typeof config.afterClose === 'function') {
config.afterClose();
}
// @ts-ignore
destroy.apply(this, args);
},
};

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import usePatchElement from '../../_util/hooks/usePatchElement';
import type { ModalFunc, ModalStaticFunctions } from '../confirm';
import { withConfirm, withError, withInfo, withSuccess, withWarn } from '../confirm';
@ -101,9 +102,9 @@ function useModal(): readonly [instance: HookAPI, contextHolder: React.ReactElem
setActionQueue((prev) => [...prev, destroyAction]);
}
},
update: (newConfig: ModalFuncProps) => {
update: (newConfig) => {
function updateAction() {
modalRef.current?.update(newConfig);
modalRef.current?.update(newConfig as ModalFuncProps);
}
if (modalRef.current) {

View File

@ -26,7 +26,7 @@ type Task =
}
| {
type: 'destroy';
key: React.Key;
key?: React.Key;
};
let taskQueue: Task[] = [];
@ -66,8 +66,8 @@ const GlobalHolder = React.forwardRef<
React.useImperativeHandle(ref, () => {
const instance: NotificationInstance = { ...api };
Object.keys(instance).forEach((method: keyof NotificationInstance) => {
instance[method] = (...args: any[]) => {
Object.keys(instance).forEach((method) => {
instance[method as keyof NotificationInstance] = (...args: any[]) => {
sync();
return (api as any)[method](...args);
};
@ -199,13 +199,13 @@ function open(config: ArgsProps) {
flushNotice();
}
function destroy(key: React.Key) {
const destroy: BaseMethods['destroy'] = (key) => {
taskQueue.push({
type: 'destroy',
key,
});
flushNotice();
}
};
interface BaseMethods {
open: (config: ArgsProps) => void;

View File

@ -8,8 +8,8 @@ import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import Button from '../../button';
describe('Popconfirm', () => {
mountTest(Popconfirm);
rtlTest(Popconfirm);
mountTest(Popconfirm as any);
rtlTest(Popconfirm as any);
const eventObject = expect.objectContaining({
target: expect.anything(),

View File

@ -1,12 +1,13 @@
import React from 'react';
import type { PopconfirmProps } from 'antd';
import { Button, message, Popconfirm } from 'antd';
const confirm = (e: React.MouseEvent<HTMLElement>) => {
const confirm: PopconfirmProps['onConfirm'] = (e) => {
console.log(e);
message.success('Click on Yes');
};
const cancel = (e: React.MouseEvent<HTMLElement>) => {
const cancel: PopconfirmProps['onCancel'] = (e) => {
console.log(e);
message.error('Click on No');
};

View File

@ -7,6 +7,7 @@ import omit from 'rc-util/lib/omit';
import type { RenderFunction } from '../_util/getRenderPropValue';
import type { ButtonProps, LegacyButtonType } from '../button/button';
import { ConfigContext } from '../config-provider';
import type { PopoverProps } from '../popover';
import Popover from '../popover';
import type { AbstractTooltipProps, TooltipRef } from '../tooltip';
import PurePanel, { Overlay } from './PurePanel';
@ -56,10 +57,7 @@ const Popconfirm = React.forwardRef<TooltipRef, PopconfirmProps>((props, ref) =>
defaultValue: props.defaultOpen ?? props.defaultVisible,
});
const settingOpen = (
value: boolean,
e?: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLDivElement>,
) => {
const settingOpen: PopoverProps['onOpenChange'] = (value, e) => {
setOpen(value, true);
onVisibleChange?.(value);
onOpenChange?.(value, e);
@ -76,10 +74,7 @@ const Popconfirm = React.forwardRef<TooltipRef, PopconfirmProps>((props, ref) =>
props.onCancel?.call(this, e);
};
const onInternalOpenChange = (
value: boolean,
e?: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLDivElement>,
) => {
const onInternalOpenChange: PopoverProps['onOpenChange'] = (value, e) => {
const { disabled = false } = props;
if (disabled) {
return;

View File

@ -7,8 +7,8 @@ import { fireEvent, render } from '../../../tests/utils';
import type { QRCodeProps } from '../interface';
describe('QRCode test', () => {
mountTest(QRCode);
rtlTest(QRCode);
mountTest(QRCode as any);
rtlTest(QRCode as any);
it('should correct render', () => {
const { container } = render(<QRCode value="test" />);

View File

@ -8,11 +8,11 @@ import Wave from '../_util/wave';
import { TARGET_CLS } from '../_util/wave/interface';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import { FormItemInputContext } from '../form/context';
import RadioGroupContext, { RadioOptionTypeContext } from './context';
import type { RadioChangeEvent, RadioProps, RadioRef } from './interface';
import useStyle from './style';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (props, ref) => {
const groupContext = React.useContext(RadioGroupContext);
@ -91,6 +91,7 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
onMouseLeave={props.onMouseLeave}
title={title}
>
{/* @ts-ignore */}
<RcCheckbox
{...radioProps}
className={classNames(radioProps.className, !isButtonType && TARGET_CLS)}

View File

@ -1,8 +1,10 @@
import * as React from 'react';
import StarFilled from '@ant-design/icons/StarFilled';
import classNames from 'classnames';
import RcRate from 'rc-rate';
import type { RateRef, RateProps as RcRateProps } from 'rc-rate/lib/Rate';
import * as React from 'react';
import type { StarProps as RcStarProps } from 'rc-rate/lib/Star';
import { ConfigContext } from '../config-provider';
import Tooltip from '../tooltip';
import useStyle from './style';
@ -12,10 +14,6 @@ export interface RateProps extends RcRateProps {
tooltips?: Array<string>;
}
interface RateNodeProps {
index: number;
}
const Rate = React.forwardRef<RateRef, RateProps>((props, ref) => {
const {
prefixCls,
@ -27,11 +25,11 @@ const Rate = React.forwardRef<RateRef, RateProps>((props, ref) => {
...rest
} = props;
const characterRender = (node: React.ReactElement, { index }: RateNodeProps) => {
const characterRender: RcStarProps['characterRender'] = (node, { index }) => {
if (!tooltips) {
return node;
}
return <Tooltip title={tooltips[index]}>{node}</Tooltip>;
return <Tooltip title={tooltips[index as number]}>{node}</Tooltip>;
};
const { getPrefixCls, direction, rate } = React.useContext(ConfigContext);

View File

@ -1,10 +1,9 @@
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
import React, { useState } from 'react';
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render } from '../../../tests/utils';
import type { SegmentedValue } from '../index';
import Segmented from '../index';
@ -30,8 +29,8 @@ function expectMatchChecked(container: HTMLElement, checkedList: boolean[]) {
}
describe('Segmented', () => {
mountTest(Segmented);
rtlTest(Segmented);
mountTest(Segmented as any);
rtlTest(Segmented as any);
beforeAll(() => {
jest.useFakeTimers();

View File

@ -1,8 +1,6 @@
import React, { useState } from 'react';
import { Select, Space } from 'antd';
const provinceData = ['Zhejiang', 'Jiangsu'];
const cityData = {
Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang'],
@ -10,13 +8,15 @@ const cityData = {
type CityName = keyof typeof cityData;
const provinceData: CityName[] = ['Zhejiang', 'Jiangsu'];
const App: React.FC = () => {
const [cities, setCities] = useState(cityData[provinceData[0] as CityName]);
const [secondCity, setSecondCity] = useState(cityData[provinceData[0] as CityName][0]);
const [secondCity, setSecondCity] = useState(cityData[provinceData[0]][0] as CityName);
const handleProvinceChange = (value: CityName) => {
setCities(cityData[value]);
setSecondCity(cityData[value][0]);
setSecondCity(cityData[value][0] as CityName);
};
const onSecondCityChange = (value: CityName) => {

View File

@ -1,4 +1,6 @@
import * as React from 'react';
import type { SliderRangeProps } from '..';
import Slider from '..';
describe('Slider.typescript', () => {
@ -13,7 +15,7 @@ describe('Slider.typescript', () => {
it('range value', () => {
const value: [number, number] = [0, 1];
const onChange = (v: [number, number]) => v;
const onChange: SliderRangeProps['onChange'] = (v) => v;
const result = (
<Slider
range

View File

@ -1,11 +1,12 @@
import React, { useState } from 'react';
import type { InputNumberProps } from 'antd';
import { Col, InputNumber, Row, Slider, Space } from 'antd';
const IntegerStep: React.FC = () => {
const [inputValue, setInputValue] = useState(1);
const onChange = (newValue: number) => {
setInputValue(newValue);
const onChange: InputNumberProps['onChange'] = (newValue) => {
setInputValue(newValue as number);
};
return (
@ -34,11 +35,11 @@ const IntegerStep: React.FC = () => {
const DecimalStep: React.FC = () => {
const [inputValue, setInputValue] = useState(0);
const onChange = (value: number) => {
if (isNaN(value)) {
const onChange: InputNumberProps['onChange'] = (value) => {
if (isNaN(value as number)) {
return;
}
setInputValue(value);
setInputValue(value as number);
};
return (

View File

@ -1,7 +1,8 @@
import React from 'react';
import type { SliderSingleProps } from 'antd';
import { Slider } from 'antd';
const formatter = (value: number) => `${value}%`;
const formatter: NonNullable<SliderSingleProps['tooltip']>['formatter'] = (value) => `${value}%`;
const App: React.FC = () => (
<>

View File

@ -261,6 +261,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
const mergedStyle: React.CSSProperties = { ...slider?.style, ...style };
return wrapCSSVar(
// @ts-ignore
<RcSlider
{...restProps}
step={restProps.step}

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import useForceUpdate from '../_util/hooks/useForceUpdate';
import { cloneElement } from '../_util/reactNode';
import type { StatisticProps } from './Statistic';
import Statistic from './Statistic';
import type { valueType, FormatConfig } from './utils';
import type { valueType } from './utils';
import { formatCountdown } from './utils';
const REFRESH_INTERVAL = 1000 / 30;
@ -56,10 +57,10 @@ const Countdown: React.FC<CountdownProps> = (props) => {
};
}, [value]);
const formatter = (formatValue: valueType, config: FormatConfig) =>
const formatter: StatisticProps['formatter'] = (formatValue, config) =>
formatCountdown(formatValue, { ...config, format });
const valueRender = (node: React.ReactElement<HTMLDivElement>) =>
const valueRender: StatisticProps['valueRender'] = (node) =>
cloneElement(node, { title: undefined });
return <Statistic {...rest} value={value} valueRender={valueRender} formatter={formatter} />;

View File

@ -1,6 +1,8 @@
import React from 'react';
import dayjs from 'dayjs';
import MockDate from 'mockdate';
import React from 'react';
import type { CountdownProps } from '..';
import Statistic from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
@ -58,8 +60,8 @@ describe('Statistic', () => {
[-3, -1112893.1212, '-1,112,893'],
[-1, -1112893, '-1,112,893'],
[-1, 1112893, '1,112,893'],
].forEach(([precision, value, expectValue]: [number, number, string]) => {
const { container } = render(<Statistic precision={precision} value={value} />);
].forEach(([precision, value, expectValue]) => {
const { container } = render(<Statistic precision={precision as any} value={value} />);
expect(container.querySelector('.ant-statistic-content-value-int')!.textContent).toEqual(
expectValue,
);
@ -168,7 +170,7 @@ describe('Statistic', () => {
const deadline = Date.now() + 10 * 1000;
let remainingTime;
const onChange = (value: number) => {
const onChange: CountdownProps['onChange'] = (value) => {
remainingTime = value;
};
render(<Statistic.Countdown value={deadline} onChange={onChange} />);

View File

@ -1,8 +1,11 @@
import React from 'react';
import CountUp from 'react-countup';
import type { StatisticProps } from 'antd';
import { Col, Row, Statistic } from 'antd';
import CountUp from 'react-countup';
const formatter = (value: number) => <CountUp end={value} separator="," />;
const formatter: StatisticProps['formatter'] = (value) => (
<CountUp end={value as number} separator="," />
);
const App: React.FC = () => (
<Row gutter={16}>

View File

@ -2,13 +2,13 @@ import * as React from 'react';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import classNames from 'classnames';
import RcSwitch from 'rc-switch';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import Wave from '../_util/wave';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import useSize from '../config-provider/hooks/useSize';
import useStyle from './style';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
export type SwitchSize = 'small' | 'default';
export type SwitchChangeEventHandler = (
@ -117,10 +117,11 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>((props, ref) =>
return wrapCSSVar(
<Wave component="Switch">
{/* @ts-ignore */}
<RcSwitch
{...restProps}
checked={checked}
onChange={changeHandler}
onChange={changeHandler as any}
prefixCls={prefixCls}
className={classes}
style={mergedStyle}

View File

@ -27,7 +27,7 @@ import Spin from '../spin';
import { useToken } from '../theme/internal';
import renderExpandIcon from './ExpandIcon';
import useContainerWidth from './hooks/useContainerWidth';
import type { FilterState } from './hooks/useFilter';
import type { FilterConfig, FilterState } from './hooks/useFilter';
import useFilter, { getFilterData } from './hooks/useFilter';
import useLazyKVMap from './hooks/useLazyKVMap';
import usePagination, { DEFAULT_PAGE_SIZE, getPaginationParam } from './hooks/usePagination';
@ -177,7 +177,7 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
const screens = useBreakpoint(needResponsive);
const mergedColumns = React.useMemo(() => {
const matched = new Set(Object.keys(screens).filter((m: Breakpoint) => screens[m]));
const matched = new Set(Object.keys(screens).filter((m) => screens[m as Breakpoint]));
return baseColumns.filter(
(c) => !c.responsive || c.responsive.some((r: Breakpoint) => matched.has(r)),
@ -226,9 +226,9 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
return null;
}, [rawData]);
const internalRefs = {
const internalRefs: NonNullable<RcTableProps['internalRefs']> = {
body: React.useRef<HTMLDivElement>(),
};
} as NonNullable<RcTableProps['internalRefs']>;
// ============================ Width =============================
const getContainerWidth = useContainerWidth(prefixCls);
@ -248,7 +248,7 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
return rowKey;
}
return (record: RecordType) => (record as any)?.[rowKey as string];
return (record: RecordType) => record?.[rowKey as string];
}, [rowKey]);
const [getRecordByKey] = useLazyKVMap(rawData, childrenColumnName, getRowKey);
@ -334,18 +334,8 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
changeEventInfo.sorterStates = sortStates;
// ============================ Filter ============================
const onFilterChange = (
filters: Record<string, FilterValue>,
filterStates: FilterState<RecordType>[],
) => {
triggerOnChange(
{
filters,
filterStates,
},
'filter',
true,
);
const onFilterChange: FilterConfig<RecordType>['onFilterChange'] = (filters, filterStates) => {
triggerOnChange({ filters, filterStates }, 'filter', true);
};
const [transformFilterColumns, filterStates, filters] = useFilter<RecordType>({
@ -619,8 +609,8 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
emptyText={emptyText}
// Internal
internalHooks={INTERNAL_HOOKS}
internalRefs={internalRefs as any}
transformColumns={transformColumns as RcTableProps<RecordType>['transformColumns']}
internalRefs={internalRefs}
transformColumns={transformColumns as any}
getContainerWidth={getContainerWidth}
/>
{bottomPaginationNode}
@ -629,4 +619,4 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
);
};
export default React.forwardRef(InternalTable) as RefInternalTable;
export default React.forwardRef(InternalTable as any) as RefInternalTable;

View File

@ -13,7 +13,6 @@ import Menu from '../../menu';
import type { SelectProps } from '../../select';
import Select from '../../select';
import Tooltip from '../../tooltip';
import type { TreeColumnFilterItem } from '../hooks/useFilter/FilterDropdown';
import type {
ColumnFilterItem,
ColumnsType,
@ -586,7 +585,7 @@ describe('Table.filter', () => {
{
...column,
defaultFilteredValue: ['Jim', 'Tom'],
onFilter: (value: string, record) => {
onFilter: (value, record) => {
if (record.children && record.children.length) {
return true;
}
@ -1563,7 +1562,7 @@ describe('Table.filter', () => {
it('with onFilter', () => {
const onFilter = jest.fn((value, record) => record.key === value);
const columns = [{ dataIndex: 'key', filteredValue: [5], onFilter }];
const columns: TableProps['columns'] = [{ dataIndex: 'key', filteredValue: [5], onFilter }];
const testData = [{ key: 1 }, { key: 3 }, { key: 5 }];
const { container } = render(<Table columns={columns} dataSource={testData} />);
@ -1793,7 +1792,7 @@ describe('Table.filter', () => {
setFilteredInfo(filters);
setSortedInfo(sorter);
};
const columns = [
const columns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',
@ -1901,7 +1900,7 @@ describe('Table.filter', () => {
],
// specify the condition of filtering result
// here is that finding the name started with `value`
onFilter: (value: string, record) => record.name?.indexOf(value) === 0,
onFilter: (value, record) => record.name?.indexOf(value as string) === 0,
sorter: (a, b) => a.name!.length - b.name!.length,
sortDirections: ['descend'],
},
@ -1924,7 +1923,7 @@ describe('Table.filter', () => {
value: 'New York',
},
],
onFilter: (value: string, record) => record.address?.indexOf(value) === 0,
onFilter: (value, record) => record.address?.indexOf(value as string) === 0,
},
];
@ -1976,7 +1975,7 @@ describe('Table.filter', () => {
value: 'New York',
},
],
onFilter: (value: string, record) => record.address?.indexOf(value) === 0,
onFilter: (value, record) => record.address?.indexOf(value as string) === 0,
},
]);
setData([
@ -2218,8 +2217,7 @@ describe('Table.filter', () => {
{ text: '节点二', value: 'node2' },
{ text: '节点三', value: 'node3' },
],
filterSearch: (input: any, record: TreeColumnFilterItem) =>
(record.title as string).includes(input),
filterSearch: (input, record) => ((record as any).title as string).includes(input),
},
],
}),

View File

@ -918,7 +918,7 @@ describe('Table.rowSelection', () => {
// https://github.com/ant-design/ant-design/issues/11384
it('should keep item even if in filter', () => {
const filterColumns = [
const filterColumns: TableProps['columns'] = [
{
title: 'Name',
dataIndex: 'name',

View File

@ -4,7 +4,7 @@ import React from 'react';
import type { ColumnType, TableProps } from '..';
import Table from '..';
import { act, fireEvent, render } from '../../../tests/utils';
import type { ColumnsType, SortOrder, TablePaginationConfig } from '../interface';
import type { SortOrder, TablePaginationConfig } from '../interface';
describe('Table.sorter', () => {
const sorterFn: ColumnType<any>['sorter'] = (a, b) =>
@ -528,10 +528,10 @@ describe('Table.sorter', () => {
// https://github.com/ant-design/ant-design/issues/11246#issuecomment-405009167
it('Allow column title as render props with sortOrder argument', () => {
const title = ({ sortOrder }: { sortOrder: SortOrder }) => (
const title: NonNullable<TableProps['columns']>[number]['title'] = ({ sortOrder }) => (
<div className="custom-title">{sortOrder}</div>
);
const columns = [{ title, key: 'group', sorter: true }];
const columns: TableProps['columns'] = [{ title, key: 'group', sorter: true }];
const testData = [
{ key: 0, name: 'Jack', age: 11 },
{ key: 1, name: 'Lucy', age: 20 },
@ -592,7 +592,7 @@ describe('Table.sorter', () => {
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const columns = [{ title: 'name', dataIndex: 'name', sorter: true }];
const columns: TableProps['columns'] = [{ title: 'name', dataIndex: 'name', sorter: true }];
const TableTest: React.FC = () => {
const [pagination, setPagination] = React.useState<TablePaginationConfig>({});
const onChange: TableProps<any>['onChange'] = (pag) => {
@ -645,11 +645,12 @@ describe('Table.sorter', () => {
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const columns = [
const columns: TableProps['columns'] = [
{
title: 'name',
dataIndex: 'name',
sorter: true,
// @ts-ignore
array: ['1', '2', 3],
render: (text: string) => text,
},
@ -705,12 +706,13 @@ describe('Table.sorter', () => {
{ key: 2, name: 'Tom', age: 21 },
{ key: 3, name: 'Jerry', age: 22 },
];
const columns = [
const columns: TableProps['columns'] = [
{
title: 'name',
dataIndex: 'name',
sorter: true,
key: 'a',
// @ts-ignore
style: { fontSize: 18 },
},
];
@ -1011,7 +1013,7 @@ describe('Table.sorter', () => {
});
it('controlled multiple group', () => {
const groupColumns: ColumnsType = [
const groupColumns: TableProps['columns'] = [
{
title: 'Math Score',
dataIndex: 'math1',

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import type { ColumnProps } from '..';
import type { TreeColumnFilterItem } from '../hooks/useFilter/FilterDropdown';
import Table from '..';
const { Column, ColumnGroup } = Table;
@ -47,8 +47,7 @@ describe('Table.typescript', () => {
{
title: 'Name',
dataIndex: 'name',
filterSearch: (input: any, record: TreeColumnFilterItem) =>
(record.title as string).includes(input),
filterSearch: (input, record) => ((record as any).title as string).includes(input),
},
];

View File

@ -13,7 +13,7 @@ interface DataType {
// In the fifth row, other columns are merged into first column
// by setting it's colSpan to be 0
const sharedOnCell = (_: DataType, index: number) => {
const sharedOnCell = (_: DataType, index?: number) => {
if (index === 1) {
return { colSpan: 0 };
}

View File

@ -1,12 +1,10 @@
import React, { useRef, useState } from 'react';
import { SearchOutlined } from '@ant-design/icons';
import type { GetRef, TableColumnsType, TableColumnType } from 'antd';
import type { InputRef, TableColumnsType, TableColumnType } from 'antd';
import { Button, Input, Space, Table } from 'antd';
import type { FilterDropdownProps } from 'antd/es/table/interface';
import Highlighter from 'react-highlight-words';
type InputRef = GetRef<typeof Input>;
interface DataType {
key: string;
name: string;

View File

@ -1,8 +1,7 @@
import React, { useContext, useEffect, useRef, useState } from 'react';
import type { GetRef } from 'antd';
import type { GetRef, InputRef } from 'antd';
import { Button, Form, Input, Popconfirm, Table } from 'antd';
type InputRef = GetRef<typeof Input>;
type FormInstance<T> = GetRef<typeof Form<T>>;
const EditableContext = React.createContext<FormInstance<any> | null>(null);
@ -53,7 +52,7 @@ const EditableCell: React.FC<EditableCellProps> = ({
useEffect(() => {
if (editing) {
inputRef.current!.focus();
inputRef.current?.focus();
}
}, [editing]);
@ -151,7 +150,7 @@ const App: React.FC = () => {
{
title: 'operation',
dataIndex: 'operation',
render: (_, record: { key: React.Key }) =>
render: (_, record) =>
dataSource.length >= 1 ? (
<Popconfirm title="Sure to delete?" onConfirm={() => handleDelete(record.key)}>
<a>Delete</a>

View File

@ -49,7 +49,7 @@ const columns: TableColumnsType<DataType> = [
],
filterMode: 'tree',
filterSearch: true,
onFilter: (value: string, record) => record.name.includes(value),
onFilter: (value, record) => record.name.includes(value as string),
width: '30%',
},
{
@ -70,7 +70,7 @@ const columns: TableColumnsType<DataType> = [
value: 'New York',
},
],
onFilter: (value: string, record) => record.address.startsWith(value),
onFilter: (value, record) => record.address.startsWith(value as string),
filterSearch: true,
width: '40%',
},

View File

@ -29,7 +29,7 @@ const columns: TableColumnsType<DataType> = [
],
filterMode: 'tree',
filterSearch: true,
onFilter: (value: string, record) => record.name.startsWith(value),
onFilter: (value, record) => record.name.startsWith(value as string),
width: '30%',
},
{
@ -50,7 +50,7 @@ const columns: TableColumnsType<DataType> = [
value: 'New York',
},
],
onFilter: (value: string, record) => record.address.startsWith(value),
onFilter: (value, record) => record.address.startsWith(value as string),
filterSearch: true,
width: '40%',
},

View File

@ -31,7 +31,7 @@ const columns: TableColumnsType<DataType> = [
value: 'John',
},
],
onFilter: (value: string, record) => record.name.indexOf(value) === 0,
onFilter: (value, record) => record.name.indexOf(value as string) === 0,
},
{
title: 'Other',

View File

@ -40,7 +40,7 @@ const columns: TableColumnsType<DataType> = [
],
// specify the condition of filtering result
// here is that finding the name started with `value`
onFilter: (value: string, record) => record.name.indexOf(value) === 0,
onFilter: (value, record) => record.name.indexOf(value as string) === 0,
sorter: (a, b) => a.name.length - b.name.length,
sortDirections: ['descend'],
},
@ -63,7 +63,7 @@ const columns: TableColumnsType<DataType> = [
value: 'New York',
},
],
onFilter: (value: string, record) => record.address.indexOf(value) === 0,
onFilter: (value, record) => record.address.indexOf(value as string) === 0,
},
];

View File

@ -78,7 +78,7 @@ const App: React.FC = () => {
{ text: 'Jim', value: 'Jim' },
],
filteredValue: filteredInfo.name || null,
onFilter: (value: string, record) => record.name.includes(value),
onFilter: (value, record) => record.name.includes(value as string),
sorter: (a, b) => a.name.length - b.name.length,
sortOrder: sortedInfo.columnKey === 'name' ? sortedInfo.order : null,
ellipsis: true,
@ -100,7 +100,7 @@ const App: React.FC = () => {
{ text: 'New York', value: 'New York' },
],
filteredValue: filteredInfo.address || null,
onFilter: (value: string, record) => record.address.includes(value),
onFilter: (value, record) => record.address.includes(value as string),
sorter: (a, b) => a.address.length - b.address.length,
sortOrder: sortedInfo.columnKey === 'address' ? sortedInfo.order : null,
ellipsis: true,

View File

@ -352,7 +352,7 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
if (typeof column.filterDropdown === 'function') {
dropdownContent = column.filterDropdown({
prefixCls: `${dropdownPrefixCls}-custom`,
setSelectedKeys: (selectedKeys: string[]) => onSelectKeys({ selectedKeys }),
setSelectedKeys: (selectedKeys) => onSelectKeys({ selectedKeys: selectedKeys as string[] }),
selectedKeys: getFilteredKeysSync(),
confirm: doFilter,
clearFilters: onReset,
@ -414,7 +414,7 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
multiple={filterMultiple}
checkStrictly={!filterMultiple}
className={`${dropdownPrefixCls}-menu`}
onCheck={onCheck}
onCheck={onCheck as any}
checkedKeys={selectedKeys}
selectedKeys={selectedKeys}
showIcon={false}

View File

@ -199,7 +199,7 @@ export function getFilterData<RecordType>(
}, data);
}
interface FilterConfig<RecordType> {
export interface FilterConfig<RecordType> {
prefixCls: string;
dropdownPrefixCls: string;
mergedColumns: ColumnsType<RecordType>;

View File

@ -1,6 +1,7 @@
import { useState } from 'react';
import type { PaginationProps } from '../../pagination';
import extendsObject from '../../_util/extendsObject';
import type { PaginationProps } from '../../pagination';
import type { TablePaginationConfig } from '../interface';
export const DEFAULT_PAGE_SIZE = 10;
@ -16,8 +17,8 @@ export function getPaginationParam(
const paginationObj = pagination && typeof pagination === 'object' ? pagination : {};
Object.keys(paginationObj).forEach((pageProp: keyof typeof paginationObj) => {
const value = mergedPagination[pageProp];
Object.keys(paginationObj).forEach((pageProp) => {
const value = mergedPagination[pageProp as keyof typeof paginationObj];
if (typeof value !== 'function') {
param[pageProp] = value;

View File

@ -23,9 +23,9 @@ function waitRaf() {
describe('Tag', () => {
mountTest(Tag);
mountTest(Tag.CheckableTag);
mountTest(Tag.CheckableTag as any);
rtlTest(Tag);
rtlTest(Tag.CheckableTag);
rtlTest(Tag.CheckableTag as any);
beforeAll(() => {
jest.useFakeTimers();

View File

@ -1,4 +1,5 @@
import { createTheme, getComputedToken } from '@ant-design/cssinjs';
import type { ThemeConfig } from '../config-provider/context';
import type { AliasToken } from './interface';
import defaultDerivative from './themes/default';
@ -11,7 +12,7 @@ const getDesignToken = (config?: ThemeConfig): AliasToken => {
...seedToken,
...config?.token,
};
return getComputedToken(mergedToken, { override: config?.token }, theme, formatToken);
return getComputedToken(mergedToken as any, { override: config?.token }, theme, formatToken);
};
export default getDesignToken;

View File

@ -1,5 +1,6 @@
import { generate } from '@ant-design/colors';
import type { DerivativeFunc } from '@ant-design/cssinjs';
import type {
ColorPalettes,
LegacyColorPalettes,
@ -7,15 +8,15 @@ import type {
PresetColorType,
SeedToken,
} from '../../interface';
import defaultAlgorithm from '../default';
import { defaultPresetColors } from '../seed';
import genColorMapToken from '../shared/genColorMapToken';
import { generateColorPalettes, generateNeutralColorPalettes } from './colors';
import defaultAlgorithm from '../default';
const derivative: DerivativeFunc<SeedToken, MapToken> = (token, mapToken) => {
const colorPalettes = Object.keys(defaultPresetColors)
.map((colorKey: keyof PresetColorType) => {
const colors = generate(token[colorKey], { theme: 'dark' });
.map((colorKey) => {
const colors = generate(token[colorKey as keyof PresetColorType], { theme: 'dark' });
return new Array(10).fill(1).reduce((prev, _, i) => {
prev[`${colorKey}-${i + 1}`] = colors[i];

View File

@ -1,6 +1,5 @@
import { generate } from '@ant-design/colors';
import genControlHeight from '../shared/genControlHeight';
import genSizeMapToken from '../shared/genSizeMapToken';
import type {
ColorPalettes,
LegacyColorPalettes,
@ -11,13 +10,15 @@ import type {
import { defaultPresetColors } from '../seed';
import genColorMapToken from '../shared/genColorMapToken';
import genCommonMapToken from '../shared/genCommonMapToken';
import { generateColorPalettes, generateNeutralColorPalettes } from './colors';
import genControlHeight from '../shared/genControlHeight';
import genFontMapToken from '../shared/genFontMapToken';
import genSizeMapToken from '../shared/genSizeMapToken';
import { generateColorPalettes, generateNeutralColorPalettes } from './colors';
export default function derivative(token: SeedToken): MapToken {
const colorPalettes = Object.keys(defaultPresetColors)
.map((colorKey: keyof PresetColorType) => {
const colors = generate(token[colorKey]);
.map((colorKey) => {
const colors = generate(token[colorKey as keyof PresetColorType]);
return new Array(10).fill(1).reduce((prev, _, i) => {
prev[`${colorKey}-${i + 1}`] = colors[i];

View File

@ -227,7 +227,9 @@ export default function genComponentStyleHook<C extends OverrideComponent>(
iconCls: `.${iconPrefixCls}`,
antCls: `.${rootPrefixCls}`,
calc,
// @ts-ignore
max,
// @ts-ignore
min,
},
cssVar ? defaultComponentToken : componentToken,
@ -247,7 +249,7 @@ export default function genComponentStyleHook<C extends OverrideComponent>(
},
);
return [wrapSSR, hashId];
return [wrapSSR as any, hashId];
};
}
@ -316,8 +318,8 @@ const genCSSVarRegister = <C extends OverrideComponent>(
const compUnitless: any = {
[prefixToken('zIndexPopup')]: true,
};
Object.keys(originUnitless).forEach((key: keyof ComponentTokenKey<C>) => {
compUnitless[prefixToken(key)] = originUnitless[key];
Object.keys(originUnitless).forEach((key) => {
compUnitless[prefixToken(key)] = originUnitless[key as keyof ComponentTokenKey<C>];
});
const CSSVarRegister: FC<CSSVarRegisterProps> = ({ rootCls, cssVar }) => {

View File

@ -1,8 +1,8 @@
import React from 'react';
import type { Dayjs } from 'dayjs';
import type { TimePickerProps } from 'antd';
import { Space, TimePicker } from 'antd';
const onChange = (time: Dayjs, timeString: string) => {
const onChange: TimePickerProps['onChange'] = (time, timeString) => {
console.log(time, timeString);
};

View File

@ -1,12 +1,12 @@
import React from 'react';
import type { Dayjs } from 'dayjs';
import type { TimePickerProps } from 'antd';
import { TimePicker } from 'antd';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { TimePicker } from 'antd';
dayjs.extend(customParseFormat);
const onChange = (time: Dayjs, timeString: string) => {
const onChange: TimePickerProps['onChange'] = (time, timeString) => {
console.log(time, timeString);
};

View File

@ -1,12 +1,12 @@
import React from 'react';
import type { TimePickerProps } from 'antd';
import { TimePicker } from 'antd';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat);
const onChange = (time: Dayjs, timeString: string) => {
const onChange: TimePickerProps['onChange'] = (time, timeString) => {
console.log(time, timeString);
};

View File

@ -1,12 +1,12 @@
import React from 'react';
import type { Dayjs } from 'dayjs';
import type { TimePickerProps } from 'antd';
import { TimePicker } from 'antd';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { TimePicker } from 'antd';
dayjs.extend(customParseFormat);
const onChange = (time: Dayjs, timeString: string) => {
const onChange: TimePickerProps['onChange'] = (time, timeString) => {
console.log(time, timeString);
};

View File

@ -1,13 +1,13 @@
import React from 'react';
import { SmileOutlined } from '@ant-design/icons';
import type { Dayjs } from 'dayjs';
import { TimePicker } from 'antd';
import type { TimePickerProps } from 'antd';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { TimePicker } from 'antd';
dayjs.extend(customParseFormat);
const onChange = (time: Dayjs, timeString: string) => {
const onChange: TimePickerProps['onChange'] = (time, timeString) => {
console.log(time, timeString);
};

Some files were not shown because too many files have changed in this diff Show More