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

如何为React Hook Form可复用组件的control属性添加严格类型?

为可复用表单组件的control属性添加严格类型定义

核心解决方案是利用TypeScript泛型结合react-hook-form提供的Control类型,让CreateForm组件能够适配任意表单数据结构,同时保留类型校验能力。

步骤1:改造CreateForm组件的类型定义

首先导入react-hook-form的Control类型,给组件的Props接口添加泛型参数,让control和onSubmit的类型与表单数据结构绑定:

import { Controller, Control, SubmitHandler } from 'react-hook-form';

// 定义带泛型的Props接口,T代表表单数据的结构类型
interface ICreateFormProps<T> {
  control: Control<T>;
  onSubmit: SubmitHandler<T>; // 使用react-hook-form提供的SubmitHandler类型,更严谨
}

// 组件接收泛型T,自动适配不同的表单结构
const CreateForm = <T,>({ onSubmit, control }: ICreateFormProps<T>) => {
  return (
    <form onSubmit={onSubmit}>
      {/* 这里的Controller可以根据业务需求扩展,比如动态渲染不同字段 */}
      <Controller
        name="name" // 字段名需对应T中的属性,也可以通过props传入实现动态配置
        render={({ field, fieldState: { error } }) => (
          <StyledTextField
            {...field}
            error={!!error}
            helperText={error?.message}
          />
        )}
        control={control}
        rules={{ required: '此字段为必填项' }} // 可选校验规则
      />
      <button type="submit">提交</button>
    </form>
  );
};

export default CreateForm;

步骤2:父组件中使用CreateForm

父组件中useForm已经指定了表单数据类型,传递control和onSubmit时,TypeScript会自动推导CreateForm的泛型参数,无需手动指定:

type CreateFaceInput = {
  name: string;
  cover: string;
};

const FaceModal = ({ open, onClose }: IFaceModalProps) => {
  const { handleSubmit, control } = useForm<CreateFaceInput>({
    defaultValues: {
      name: '',
      cover: '',
    },
  });

  const onSubmit: SubmitHandler<CreateFaceInput> = (data) => {
    // 处理表单提交逻辑
  };

  return (
    <CreateForm
      onSubmit={handleSubmit(onSubmit)}
      control={control}
    />
  );
};

如果是其他表单结构的场景,比如{face: string, address: string},只需修改父组件的表单类型定义即可,CreateForm会自动适配:

type CreateAddressInput = {
  face: string;
  address: string;
};

const AddressModal = ({ open, onClose }) => {
  const { handleSubmit, control } = useForm<CreateAddressInput>({
    defaultValues: {
      face: '',
      address: '',
    },
  });

  const onSubmit: SubmitHandler<CreateAddressInput> = (data) => {
    // 处理地址表单提交
  };

  return (
    <CreateForm
      onSubmit={handleSubmit(onSubmit)}
      control={control}
    />
  );
};

可选优化:动态渲染表单字段

如果需要CreateForm完全根据不同的表单结构动态生成输入项,可以新增字段配置的Props,让父组件传入需要渲染的字段信息:

// 新增字段配置类型
interface FormFieldConfig<T> {
  name: keyof T;
  label: string;
  type?: 'text' | 'email' | 'password';
  rules?: any; // 或者使用react-hook-form的RegisterOptions<T>类型
}

// 更新Props接口
interface ICreateFormProps<T> {
  control: Control<T>;
  onSubmit: SubmitHandler<T>;
  fields: FormFieldConfig<T>[];
}

// 修改组件渲染逻辑
const CreateForm = <T,>({ onSubmit, control, fields }: ICreateFormProps<T>) => {
  return (
    <form onSubmit={onSubmit}>
      {fields.map(field => (
        <Controller
          key={field.name as string}
          name={field.name}
          render={({ field: ctrlField, fieldState: { error } }) => (
            <StyledTextField
              {...ctrlField}
              label={field.label}
              type={field.type || 'text'}
              error={!!error}
              helperText={error?.message}
            />
          )}
          control={control}
          rules={field.rules}
        />
      ))}
      <button type="submit">提交</button>
    </form>
  );
};

父组件使用时传入字段配置:

<CreateForm
  onSubmit={handleSubmit(onSubmit)}
  control={control}
  fields={[
    { name: 'name', label: '名称', rules: { required: '名称不能为空' } },
    { name: 'cover', label: '封面地址', rules: { required: '封面地址不能为空' } },
  ]}
/>

内容的提问来源于stack exchange,提问作者qweezz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:35:10