Skip to content

Commit fbbb2e2

Browse files
authored
refactor(util): use shared type guards for runtime checks (ant-design#57835)
* refactor(util): use shared type guards for runtime checks * update * update * update
1 parent 9d9c0ae commit fbbb2e2

47 files changed

Lines changed: 173 additions & 181 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type * as React from 'react';
22

3+
import { isFunction } from './is';
4+
35
export type RenderFunction = () => React.ReactNode;
46

57
export const getRenderPropValue = (
@@ -8,6 +10,5 @@ export const getRenderPropValue = (
810
if (!propValue) {
911
return null;
1012
}
11-
12-
return typeof propValue === 'function' ? propValue() : propValue;
13+
return isFunction(propValue) ? propValue() : propValue;
1314
};

components/_util/hooks/useMergeSemantic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { clsx } from 'clsx';
33

4-
import { isPlainObject } from '../is';
4+
import { isFunction, isPlainObject } from '../is';
55
import type { AnyObject, EmptyObject, ValidChar } from '../type';
66

77
export type SemanticSchema = { _default?: string } & {
@@ -103,7 +103,7 @@ export const resolveStyleOrClass = <T extends AnyObject>(
103103
value: T | ((config: any) => T),
104104
info: { props: AnyObject },
105105
) => {
106-
return typeof value === 'function' ? value(info) : value;
106+
return isFunction(value) ? value(info) : value;
107107
};
108108

109109
type MaybeFn<T, P> = T | ((info: { props: P }) => T) | undefined;

components/_util/responsiveObserver.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import type { GlobalToken } from '../theme/internal';
44
import { useToken } from '../theme/internal';
5+
import { isFunction } from './is';
56

67
export const responsiveArray = ['xxxl', 'xxl', 'xl', 'lg', 'md', 'sm', 'xs'] as const;
78
export const responsiveArrayReversed = [...responsiveArray].reverse();
@@ -131,7 +132,7 @@ const useResponsiveObserver = () => {
131132
this.dispatch({ ...screens, [screen]: matches });
132133
};
133134
const mql = window.matchMedia(mediaQuery);
134-
if (typeof mql?.addEventListener === 'function') {
135+
if (isFunction(mql.addEventListener)) {
135136
mql.addEventListener('change', listener);
136137
}
137138
this.matchHandlers[mediaQuery] = { mql, listener };
@@ -141,7 +142,7 @@ const useResponsiveObserver = () => {
141142
unregister() {
142143
Object.values(responsiveMap).forEach((mediaQuery) => {
143144
const handler = this.matchHandlers[mediaQuery];
144-
if (typeof handler?.mql?.removeEventListener === 'function') {
145+
if (isFunction(handler?.mql.removeEventListener)) {
145146
handler.mql.removeEventListener('change', handler?.listener);
146147
}
147148
});

components/_util/scrollTo.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import raf from '@rc-component/util/lib/raf';
22

33
import { easeInOutCubic } from './easings';
44
import getScroll, { isWindow } from './getScroll';
5+
import { isFunction } from './is';
56

67
interface ScrollToOptions {
78
/** Scroll container, default as window */
@@ -33,7 +34,7 @@ export default function scrollTo(y: number, options: ScrollToOptions = {}) {
3334
}
3435
if (time < duration) {
3536
rafId = raf(frameFunc);
36-
} else if (typeof callback === 'function') {
37+
} else if (isFunction(callback)) {
3738
callback();
3839
}
3940
};

components/anchor/Anchor.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import scrollIntoView from 'scroll-into-view-if-needed';
66
import getScroll from '../_util/getScroll';
77
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
88
import { useMergeSemantic } from '../_util/hooks';
9-
import { isPlainObject } from '../_util/is';
9+
import { isFunction, isNumber, isPlainObject } from '../_util/is';
1010
import scrollTo from '../_util/scrollTo';
1111
import { devUseWarning } from '../_util/warning';
1212
import Affix from '../affix';
@@ -257,7 +257,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
257257
}
258258

259259
// https://github.com/ant-design/ant-design/issues/30584
260-
const newLink = typeof getCurrentAnchor === 'function' ? getCurrentAnchor(link) : link;
260+
const newLink = isFunction(getCurrentAnchor) ? getCurrentAnchor(link) : link;
261261
setActiveLink(newLink);
262262
activeLinkRef.current = newLink;
263263

@@ -273,7 +273,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
273273

274274
const currentActiveLink = getInternalCurrentAnchor(
275275
links,
276-
targetOffset !== undefined ? targetOffset : offsetTop || 0,
276+
isNumber(targetOffset) ? targetOffset : offsetTop || 0,
277277
bounds,
278278
);
279279

@@ -304,7 +304,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
304304
const scrollTop = getScroll(container);
305305
const eleOffsetTop = getOffsetTop(targetElement, container);
306306
let y = scrollTop + eleOffsetTop;
307-
y -= targetOffset !== undefined ? targetOffset : offsetTop || 0;
307+
y -= isNumber(targetOffset) ? targetOffset : offsetTop || 0;
308308
animatingRef.current = true;
309309
scrollRequestIdRef.current = scrollTo(y, {
310310
getContainer: getCurrentContainer,
@@ -388,7 +388,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
388388
}, [dependencyListItem]);
389389

390390
React.useEffect(() => {
391-
if (typeof getCurrentAnchor === 'function') {
391+
if (isFunction(getCurrentAnchor)) {
392392
setCurrentActiveLink(getCurrentAnchor(activeLinkRef.current || ''));
393393
}
394394
}, [getCurrentAnchor]);

components/calendar/generateCalendar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { clsx } from 'clsx';
88

99
import { useMergeSemantic } from '../_util/hooks';
1010
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
11+
import { isFunction } from '../_util/is';
1112
import type { AnyObject } from '../_util/type';
1213
import { devUseWarning } from '../_util/warning';
1314
import { useComponentConfig } from '../config-provider/context';
@@ -261,7 +262,6 @@ const generateCalendar = <DateType extends AnyObject>(generateConfig: GenerateCo
261262
if (dateFullCellRender) {
262263
return dateFullCellRender(date);
263264
}
264-
265265
return (
266266
<div
267267
className={clsx(`${prefixCls}-cell-inner`, `${calendarPrefixCls}-date`, {
@@ -272,7 +272,7 @@ const generateCalendar = <DateType extends AnyObject>(generateConfig: GenerateCo
272272
{String(generateConfig.getDate(date)).padStart(2, '0')}
273273
</div>
274274
<div className={`${calendarPrefixCls}-date-content`}>
275-
{typeof cellRender === 'function' ? cellRender(date, info) : dateCellRender?.(date)}
275+
{isFunction(cellRender) ? cellRender(date, info) : dateCellRender?.(date)}
276276
</div>
277277
</div>
278278
);
@@ -310,7 +310,7 @@ const generateCalendar = <DateType extends AnyObject>(generateConfig: GenerateCo
310310
{months[generateConfig.getMonth(date)]}
311311
</div>
312312
<div className={`${calendarPrefixCls}-date-content`}>
313-
{typeof cellRender === 'function' ? cellRender(date, info) : monthCellRender?.(date)}
313+
{isFunction(cellRender) ? cellRender(date, info) : monthCellRender?.(date)}
314314
</div>
315315
</div>
316316
);

components/collapse/Collapse.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { clsx } from 'clsx';
88

99
import { useMergeSemantic } from '../_util/hooks';
1010
import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks';
11+
import { isFunction } from '../_util/is';
1112
import initCollapseMotion from '../_util/motion';
1213
import { cloneElement } from '../_util/reactNode';
1314
import { devUseWarning } from '../_util/warning';
@@ -155,15 +156,14 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
155156

156157
const renderExpandIcon = React.useCallback(
157158
(panelProps: PanelProps = {}) => {
158-
const icon =
159-
typeof mergedExpandIcon === 'function' ? (
160-
mergedExpandIcon(panelProps)
161-
) : (
162-
<RightOutlined
163-
rotate={panelProps.isActive ? (direction === 'rtl' ? -90 : 90) : undefined}
164-
aria-label={panelProps.isActive ? 'expanded' : 'collapsed'}
165-
/>
166-
);
159+
const icon = isFunction(mergedExpandIcon) ? (
160+
mergedExpandIcon(panelProps)
161+
) : (
162+
<RightOutlined
163+
rotate={panelProps.isActive ? (direction === 'rtl' ? -90 : 90) : undefined}
164+
aria-label={panelProps.isActive ? 'expanded' : 'collapsed'}
165+
/>
166+
);
167167
return cloneElement(icon, (oriProps) => ({
168168
className: clsx(oriProps.className, `${prefixCls}-arrow`),
169169
}));

components/color-picker/ColorPickerPanel.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { FC } from 'react';
22
import React from 'react';
33

4+
import { isFunction } from '../_util/is';
45
import Divider from '../divider';
56
import PanelPicker from './components/PanelPicker';
67
import PanelPresets from './components/PanelPresets';
@@ -9,8 +10,7 @@ import type { PanelPickerContextProps, PanelPresetsContextProps } from './contex
910
import type { ColorPickerProps } from './interface';
1011

1112
export interface ColorPickerPanelProps
12-
extends PanelPickerContextProps,
13-
Omit<PanelPresetsContextProps, 'onChange'> {
13+
extends PanelPickerContextProps, Omit<PanelPresetsContextProps, 'onChange'> {
1414
onClear?: () => void;
1515
panelRender?: ColorPickerProps['panelRender'];
1616
}
@@ -104,12 +104,9 @@ const ColorPickerPanel: FC<ColorPickerPanelProps> = (props) => {
104104
<PanelPickerContext.Provider value={panelContext}>
105105
<PanelPresetsContext.Provider value={presetContext}>
106106
<div className={colorPickerPanelPrefixCls}>
107-
{typeof panelRender === 'function'
107+
{isFunction(panelRender)
108108
? panelRender(innerPanel, {
109-
components: {
110-
Picker: PanelPicker,
111-
Presets: PanelPresets,
112-
},
109+
components: { Picker: PanelPicker, Presets: PanelPresets },
113110
})
114111
: innerPanel}
115112
</div>

components/color-picker/components/ColorTrigger.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ColorBlock } from '@rc-component/color-picker';
55
import pickAttrs from '@rc-component/util/lib/pickAttrs';
66
import { clsx } from 'clsx';
77

8+
import { isFunction } from '../../_util/is';
89
import { useLocale } from '../../locale';
910
import type { AggregationColor } from '../color';
1011
import type {
@@ -61,7 +62,7 @@ const ColorTrigger = forwardRef<HTMLDivElement, ColorTriggerProps>((props, ref)
6162
return '';
6263
}
6364

64-
if (typeof showText === 'function') {
65+
if (isFunction(showText)) {
6566
return showText(color);
6667
}
6768

components/config-provider/hooks/useSize.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22

3+
import { isFunction, isString } from '../../_util/is';
34
import type { SizeType } from '../SizeContext';
45
import SizeContext from '../SizeContext';
56

@@ -11,10 +12,10 @@ const useSize = <T extends string | undefined | number | object>(
1112
if (!customSize) {
1213
return size as T;
1314
}
14-
if (typeof customSize === 'string') {
15+
if (isString(customSize)) {
1516
return customSize ?? size;
1617
}
17-
if (typeof customSize === 'function') {
18+
if (isFunction(customSize)) {
1819
return customSize(size);
1920
}
2021
return size as T;

0 commit comments

Comments
 (0)