antd5 提供了一系列实用的TypeScript类型工具,本文将详细介绍这些工具的使用方法和实现原理。 欢迎各位大佬留言指正~
核心类型工具
- GetProps
- GetProp
- GetRef
- GetContextProps
- GetContextProp
1. GetProps - 获取组件的Props类型
GetProps工具可以从组件类型中提取完整的Props类型定义。这对于组件封装和类型继承特别有用。
实现原理
export type GetProps<T extends React.ComponentType<any> | object> = T extends React.ComponentType<infer P>
? P
: T extends object
? T
: never;
该工具利用条件类型和infer关键字推断组件的Props类型:
- 如果T是React组件类型,使用
infer P推断并返回其Props类型 - 如果T已经是对象类型,则直接返回T
- 否则返回never
使用示例
import { Button } from 'my-ui';
import type { GetProps } from 'my-ui';
// 获取Button组件的Props类型
type ButtonProps = GetProps<typeof Button>;
// 使用提取的类型
const onClick: ButtonProps['onClick'] = (e) => {
console.log('Button clicked', e);
};
// 获取子组件的Props类型
type CheckboxGroupProps = GetProps<typeof Checkbox.Group>;
2. GetProp - 获取组件的单个Prop类型
GetProp工具可以提取组件特定属性的类型,并自动处理非空情况,确保类型安全。
实现原理
export type GetProp<
T extends React.ComponentType<any> | object,
PropName extends keyof GetProps<T>
> = NonNullable<GetProps<T>[PropName]>;
该工具的实现过程:
- 首先使用
GetProps<T>获取组件的所有props类型 - 然后使用索引访问
GetProps<T>[PropName]获取特定属性的类型 - 最后用
NonNullable<T>处理掉null和undefined类型,确保类型安全
使用示例
import { Select } from 'my-ui';
import type { GetProp, SelectProps } from 'my-ui';
// 提取数组选项类型
type SelectOption = GetProp<typeof Select, 'options'>[number];
const option: SelectOption = { label: '选项1', value: '1' };
// 提取事件处理函数类型
const handleChange: GetProp<typeof Select, 'onChange'> = (value) => {
console.log(value); // 类型安全,不用担心undefined
};
// 以下两种方式均可获取options类型
type SelectOption1 = GetProp<SelectProps, 'options'>[number];
type SelectOption2 = GetProp<typeof Select, 'options'>[number];
实际示例中的应用:
// 在Checkbox组件示例中使用
const onChange: GetProp<typeof Checkbox.Group, 'onChange'> = checkedValues => {
setCheckedList(checkedValues as string[]);
console.log('选中的值: ', checkedValues);
};
const onCheckAllChange: GetProp<typeof Checkbox, 'onChange'> = e => {
setCheckedList(e.target.checked ? plainOptions : []);
setIndeterminate(false);
setCheckAll(e.target.checked);
};
3. GetRef - 获取组件的Ref类型
GetRef工具可以提取组件的Ref类型,便于正确地使用ref引用组件实例。
实现原理
type ReactRefComponent<Props extends { ref?: React.Ref<any> | string }> = (props: Props) => React.ReactNode;
type ExtractRefAttributesRef<T> = T extends React.RefAttributes<infer P> ? P : never;
export type GetRef<T extends ReactRefComponent<any> | React.Component<any>> = T extends React.Component<any>
? T
: T extends React.ComponentType<infer P>
? ExtractRefAttributesRef<P>
: never;
该工具的实现过程:
- 定义辅助类型
ReactRefComponent用于描述函数组件 - 定义辅助类型
ExtractRefAttributesRef用于从RefAttributes中提取具体的Ref类型 - 根据组件类型分别处理类组件和函数组件的ref类型
使用示例
import { Input } from 'my-ui';
import type { GetRef } from 'my-ui';
import { useRef } from 'react';
// 获取Input组件的Ref类型
type InputRef = GetRef<typeof Input>;
// 使用提取的类型
const inputRef = useRef<InputRef>(null);
// 可以安全地访问ref上的方法
const focusInput = () => {
inputRef.current?.focus();
};
4. GetContextProps/GetContextProp - 获取Context类型
这两个工具用于从React Context中提取类型信息。
实现原理
export type GetContextProps<T> = T extends React.Context<infer P> ? P : never;
export type GetContextProp<
T extends React.Context<any>,
PropName extends keyof GetContextProps<T>
> = NonNullable<GetContextProps<T>[PropName]>;
使用示例
import { ThemeContext } from 'my-ui';
import type { GetContextProps, GetContextProp } from 'my-ui';
// 获取Context的Props类型
type ThemeContextProps = GetContextProps<typeof ThemeContext>;
// 获取Theme上下文中的color属性类型
type ThemeColor = GetContextProp<typeof ThemeContext, 'color'>;
应用场景
1. 组件封装与扩展
当需要基于现有组件进行封装或扩展时,可以使用GetProps获取原组件的完整Props类型:
interface MyButtonProps extends GetProps<typeof Button> {
extraProp?: string;
}
const MyButton: React.FC<MyButtonProps> = (props) => {
// 实现逻辑
};
2. 类型安全的事件处理
使用GetProp确保事件处理函数具有正确的类型:
// 确保onChange函数的参数类型与组件期望的一致
const handleChange: GetProp<typeof Input, 'onChange'> = (e) => {
// 类型安全的事件处理
};
3. Ref引用管理
使用GetRef确保正确地使用组件提供的ref方法:
const formRef = useRef<GetRef<typeof Form>>(null);
// 安全地调用ref方法
const validateForm = () => {
formRef.current?.validate();
};
4. 数组选项类型
从选择类组件中提取选项类型:
// 从Select组件的options属性提取单个选项的类型
type Option = GetProp<typeof Select, 'options'>[number];
// 创建类型安全的选项数组
const options: Option[] = [
{ label: '选项1', value: '1' },
{ label: '选项2', value: '2' }
];