在使用 antd 组件的时候,同事遇到一个问题,Radio
组件的 onChange
事件处理函数,传递的参数是一个事件对象,无法推导类型:
import { Radio } from "antd";
import * as React from "react";
type Props = {
name: string;
}
const HelloWorld: React.FC<Props> = ({ name }) => {
const [value, setValue] = React.useState(0);
// 这边的形参 e 会提示隐式 any
const onChange = (e) => {
setValue(e.target.value);
}
return (
<Radio.Group onChange={onChange} value={value}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
</Radio.Group>
)
}
先尝试了一下 React 的事件类型声明:
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
setValue(e.target.value);
}
const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
setValue(e.target.value);
}
试验之后发现两种方法都不行,看来 antd 内部应该是对原生事件类型进行了封装,导致和 React 合成事件无法匹配上了。
最后同事通过导入 RadioChangeEvent
解决问题:
import { RadioChangeEvent } from "antd/lib/radio";
const onChange = (e: RadioChangeEvent) => {
setValue(e.target.value);
}
那么这边有一个问题,如果第三方库没有导出 Type ,如何获取到类型呢?这边提供两种方案。
1. 使用 typeof 推导
可以使用 typeof
推导出 type :
import { Radio } from "antd";
// 使用 typeof 推导出 Radio.Group 的类型
// 使用 React.ComponentProps 获取到 props 的类型
type RadioGroupProps = React.ComponentProps<typeof Radio.Group>;
// 使用 Pick 工具类型过滤出 onChange 类型
type EventProps = Pick<RadioGroupProps, "onChange">;
// 获取 onChange 类型
// type ChangeEvent = ((e: RadioChangeEvent) => void) | undefined
type ChangeEvent = EventProps["onChange"];
const onChange:ChangeEvent = (e) => {
setValue(e.target.value);
}
这样就基本上可以了。但是如果想直接获取到参数的类型呢?可以使用 TS 提供的 Parameters
获取到函数参数类型:
import { Radio } from "antd";
type RadioGroupProps = React.ComponentProps<typeof Radio.Group>;
type ChangeEvent = RadioGroupProps["onChange"];
// 上一步获取到的类型是包含 undefined 的联合类型
// 需要先把 undefined 过滤掉
// 最后得到一个包含参数类型的元组
type ChangeFnParams = Parameters<NonNullable<ChangeEvent>>[0];
const onChange = (e: ChangeFnParams) => {
setValue(e.target.value);
}
此外 TS 还提供了 ReturnType
工具类,可以获取到函数的返回类型:
type IsArray = typeof Array.isArray;
type Return = ReturnType<IsArray>; // type Return = boolean
type ParseInt = typeof parseInt;
type Return = ReturnType<ParseInt>; // type Return = number
type MathMax = typeof Math.max;
type Return = ReturnType<MathMax>; // type Return = number
2. 参数解构
这种方法相信很多同学都用过,先对参数解构,然后声明解构之后的参数类型即可:
type ChangeEvent = {
target: HTMLInputElement;
}
const onChange = ({ target }: ChangeEvent) => {
setValue(target.value);
}
上面这样等于还套了一层,可以直接解构到 value
:
type ChangeEvent = {
target: {
value: string;
}
}
const onChange = ({ target: { value } }: ChangeEvent) => {
setValue(value);
}