如何为Formik子组件的formik属性正确定义泛型类型?
解决Formik子表单的类型定义问题
你可以通过泛型约束来实现子组件的类型安全,既不需要强制类型断言,又能保证子组件只依赖SmallerFormTypes的字段,同时兼容父表单的交叉类型。
方案一:泛型子组件
定义子组件的props时,用泛型约束Formik的泛型类型必须包含SmallerFormTypes的所有字段:
import { FormikProps } from 'formik'; // 子组件props的泛型定义 interface SmallerFormComponentProps<T extends SmallerFormTypes> { formik: FormikProps<T>; } // 子组件实现 const SmallerFormComponent = <T extends SmallerFormTypes>({ formik }: SmallerFormComponentProps<T>) => { // 这里可以安全访问formik.values中属于SmallerFormTypes的字段,类型完全推导 const { values, handleChange, setFieldValue } = formik; return ( <div> <input name="smallerField" // 假设SmallerFormTypes包含smallerField字段 value={values.smallerField} onChange={handleChange} /> </div> ); };
父组件使用
父表单的FormikProps<BiggerFormSpecificTypes & SmallerFormTypes>自动满足T extends SmallerFormTypes的约束,直接传递即可,无需额外处理:
const formik = useFormik<BiggerFormSpecificTypes & SmallerFormTypes>({ initialValues: { // 包含Bigger和Smaller的初始值 }, onSubmit: (values) => { // 处理提交 }, }); <SmallerFormComponent formik={formik} />
方案二:限定Formik的Values类型
如果你不需要泛型的灵活性,也可以直接定义一个类型,要求Formik的values必须包含SmallerFormTypes:
import { FormikProps } from 'formik'; // 定义兼容所有包含SmallerFormTypes的Formik实例的类型 type FormikCompatibleWithSmaller = FormikProps<SmallerFormTypes & Record<string, unknown>>; interface SmallerFormComponentProps { formik: FormikCompatibleWithSmaller; } // 子组件使用时,访问SmallerFormTypes的字段依然是类型安全的 const SmallerFormComponent = ({ formik }: SmallerFormComponentProps) => { const { values, handleChange } = formik; // values.smallerField 类型正确 return <input name="smallerField" value={values.smallerField} onChange={handleChange} />; };
为什么不推荐直接断言?
你之前用formik as FormikProps<SmallerFormTypes>的方式会丢失父表单的类型信息,而且如果后续父表单的类型发生变化(比如新增字段),子组件无法感知,容易引发类型错误。而上面的两种方案既能保证子组件的类型安全,又能兼容父表单的交叉类型。
内容的提问来源于stack exchange,提问作者Peter Kim
相关产品推荐
相关产品推荐

