如何从函数参数的对象键推导类型?(react-final-form场景)
嘿,我刚好在react-final-form里折腾过类似的类型推导需求,咱们一步步来搞定它!
从FormSpy回调的对象键自动推导TypeScript类型
先明确你的场景:用FormSpy订阅表单的部分状态(比如values、touched这类键),希望TypeScript能根据你订阅的键,自动推导onChange回调参数的类型,不用手动重复定义。
第一步:复用/定义表单状态的基础类型
react-final-form本身提供了泛型的FormState类型,你可以直接结合自己的表单值类型来用:
import { FormState } from 'react-final-form'; // 定义你的表单字段值类型 type MyFormValues = { username: string; email: string; password: string; }; // 基于表单值类型,得到完整的表单状态类型 type MyFullFormState = FormState<MyFormValues>;
这个MyFullFormState会包含values、touched、errors、dirty等所有react-final-form的表单状态字段。
第二步:创建订阅状态的类型工具
我们用TypeScript内置的Pick工具类型,来提取订阅键对应的状态片段:
// 这个工具类型会从完整表单状态中,提取你指定的键对应的类型 type SubscribedFormState<T extends FormState<any>, K extends keyof T> = Pick<T, K>;
第三步:带类型推导的FormSpy使用方式
你有两种选择:要么封装一个自定义的Typed FormSpy组件,要么在原生组件里手动指定泛型。
选项1:封装自定义Typed FormSpy(推荐,更易用)
封装后每次使用都不用重复写泛型,类型会自动推导:
import { FormSpy as OriginalFormSpy, FormSpyProps } from 'react-final-form'; // 定义带类型约束的props类型 type TypedFormSpyProps<T extends FormState<any>, K extends keyof T> = Omit<FormSpyProps, 'subscription' | 'onChange'> & { subscription: Record<K, true>; onChange: (state: SubscribedFormState<T, K>) => void; }; // 封装自定义FormSpy组件 export const TypedFormSpy = <T extends FormState<any>, K extends keyof T>(props: TypedFormSpyProps<T, K>) => { return <OriginalFormSpy {...props} />; };
使用的时候,只要传入你的表单状态类型,订阅对应的键,onChange的参数类型就会自动出来:
<TypedFormSpy<MyFullFormState, 'values' | 'touched'> subscription={{ values: true, touched: true }} onChange={(state) => { // 这里state的类型自动是 { values: MyFormValues; touched: Partial<Record<keyof MyFormValues, boolean>> } console.log(state.values.username); // 类型正确,不会报错 console.log(state.touched.email); // 同样类型安全 }} />
选项2:直接使用原生FormSpy
如果不想封装组件,也可以在使用原生FormSpy时手动指定类型:
<FormSpy subscription={{ errors: true, dirty: true }} onChange={(state: SubscribedFormState<MyFullFormState, 'errors' | 'dirty'>) => { // state的类型自动是 { errors: Partial<Record<keyof MyFormValues, string>>; dirty: boolean } console.log(state.errors.password); console.log(state.dirty); }} />
为什么这么做?
- 类型安全:当你修改
subscription里的键时,onChange的参数类型会自动更新,避免手动维护类型导致的错误。 - 减少重复代码:不用每次都手动写回调参数的类型,TypeScript帮你自动推导。
内容的提问来源于stack exchange,提问作者Martin Lehmann
相关产品推荐
相关产品推荐

