Formik封装Antd Input报TS2322类型不兼容错误如何解决
问题现象
编写基于Formik的自定义Antd Input组件时,触发TypeScript TS2322类型报错,原始组件代码如下:
import { Input } from 'antd'; import { useField, FieldHookConfig } from 'formik'; const Text = ({ ...props }: FieldHookConfig<string>) => { const [field] = useField(props); return <Input {...field} {...props} />; }; export default FormTextField;
完整报错信息:
TS2322: Type '{ className: string | undefined; ref?: LegacyRef<HTMLInputElement> | undefined; key?: Key | null | undefined; accept?: string | undefined; ... 288 more ...; innerRef?: ((instance: any) => void) | undefined; } | { ...; } | { ...; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Input> & Pick<Readonly<InputProps>, "color" | ... 290 more ... | "bordered"> & InexactPartial<...> & InexactPartial<...>'. Type '{ className: string | undefined; ref?: LegacyRef<HTMLInputElement> | undefined; key?: Key | null | undefined; accept?: string | undefined; alt?: string | undefined; ... 287 more ...; innerRef?: ((instance: any) => void) | undefined; }' is not assignable to type 'IntrinsicClassAttributes<Input>'. Types of property 'ref' are incompatible. Type 'LegacyRef<HTMLInputElement> | undefined' is not assignable to type 'LegacyRef<Input> | undefined'. Type '(instance: HTMLInputElement | null) => void' is not assignable to type 'LegacyRef<Input> | undefined'. Type '(instance: HTMLInputElement | null) => void' is not assignable to type '(instance: Input | null) => void'. Types of parameters 'instance' and 'instance' are incompatible. Type 'Input | null' is not assignable to type 'HTMLInputElement | null'. Type 'Input' is missing the following properties from type 'HTMLInputElement': accept, align, alt, autocomplete, and 329 more.
报错根因
- Formik的
useField返回的field对象中携带的ref指向原生HTMLInputElementDOM节点 - Antd的
Input是封装后的组件,它本身的ref属性要求指向Antd Input组件实例,而非原生DOM节点,要获取原生输入框DOM需要通过innerRef属性传入 - 直接全量展开
field属性时,类型不匹配的ref被透传给Antd Input,触发TS类型校验失败 - 代码本身存在额外问题:组件定义名是
Text,导出名是FormTextField,命名不一致
修复方案
根据是否需要使用Formik提供的ref,选择对应实现:
方案1:需要保留ref绑定(推荐)
从field中解构出ref,将剩余属性透传给Input,同时把ref绑定到Antd Input提供的innerRef属性上,同时合并Antd Input的Props类型,避免类型缺失:
import { Input } from 'antd'; import { useField, FieldHookConfig } from 'formik'; import type { InputProps } from 'antd/es/input'; // 合并Formik字段配置与Antd Input原生属性类型 type AppFormInputProps = FieldHookConfig<string> & InputProps; const FormTextField = (props: AppFormInputProps) => { const [field] = useField(props); // 分离出ref和其他表单绑定属性 const { ref: formikInputRef, ...restFieldProps } = field; return ( <Input {...restFieldProps} {...props} // Antd Input通过innerRef接收原生DOM的ref innerRef={formikInputRef} /> ); }; export default FormTextField;
方案2:不需要使用ref(最简实现)
绝大多数表单场景只需要Formik同步值、校验状态,不需要用到field返回的ref,此时直接将ref解构丢弃即可:
import { Input } from 'antd'; import { useField, FieldHookConfig } from 'formik'; import type { InputProps } from 'antd/es/input'; type AppFormInputProps = FieldHookConfig<string> & InputProps; const FormTextField = (props: AppFormInputProps) => { const [field] = useField(props); // 排除不需要的ref属性,避免类型冲突 const { ref: _, ...restFieldProps } = field; return <Input {...restFieldProps} {...props} />; }; export default FormTextField;
注意:不要直接用
@ts-ignore忽略这类报错,否则后续组件属性变更、ref调用时容易出现运行时错误。
内容的提问来源于stack exchange,提问作者A curious student
相关产品推荐
相关产品推荐

