You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从函数参数的对象键推导类型?(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:06:50