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

如何为自定义React Hook Form钩子配置泛型Yup对象Schema以实现表单字段类型提示?

如何为自定义React Hook Form钩子配置泛型Yup对象Schema以实现表单字段类型提示?

我完全懂你遇到的困扰——自定义的useCustomForm钩子能用,但getValues()没法自动提示表单字段,写代码的时候全靠记忆,太影响效率了。咱们来调整一下泛型配置,把这个问题彻底解决掉。

问题根源分析

你之前尝试给useCustomForm加泛型,但选错了参数类型——你传入的其实是Yup的字段定义对象(ObjectShape),不是已经用yup.object()创建好的完整ObjectSchema,所以TS才会抛出约束错误。咱们需要让泛型和传入的字段定义对象正确关联,同时自动推断出表单字段的类型。

修改后的自定义Hook代码

直接上调整后的完整代码,我会逐步解释关键改动:

import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

// 泛型Shape约束为Yup的ObjectShape(即表单字段的定义对象类型)
export const useCustomForm = <Shape extends yup.ObjectShape>(shape: Shape) => {
  // 用传入的字段定义创建完整的Yup Schema
  const formSchema = yup.object(shape).required();
  // 从Schema自动推断出表单字段的具体类型
  type FormFields = yup.InferType<typeof formSchema>;

  const {
    register,
    handleSubmit,
    getValues,
    formState: { errors },
  } = useForm<FormFields>({
    resolver: yupResolver(formSchema),
  });

  const onFormSubmit = (e: React.FormEvent, onSubmit: () => void) => {
    e.preventDefault();
    handleSubmit(onSubmit)();
  };

  return {
    register,
    onSubmit: onFormSubmit,
    getValues,
    errors,
  };
};

关键改动说明

  1. 泛型约束:用<Shape extends yup.ObjectShape>确保传入的参数是符合要求的Yup字段定义对象,每个属性都是一个Yup Schema(比如yup.string())。
  2. 自动推断类型:通过yup.InferType<typeof formSchema>从创建好的Schema里自动提取出表单字段的类型(比如{ username: string; password: string; ... }),这样useForm就能拿到准确的类型信息。
  3. 无需手动传泛型:TS会根据你传入的字段定义对象自动推断出FormFields的类型,完全不用额外写类型声明。

在SignUpForm中使用(类型提示生效)

现在你再调用useCustomForm,getValues()就会自动提示所有表单字段了:

export const SignUpForm: FC = () => {
  const router = useRouter();

  const { register, onSubmit, getValues, errors } = useCustomForm({
    username: yup.string().min(3).max(50).required(),
    password: yup.string().min(6).max(50).required(),
    password_confirmation: yup
      .string()
      .min(6)
      .max(50)
      .required()
      .oneOf([yup.ref('password')], 'Password does not match!'),
    is_admin: yup.string(),
  });

  const onSignUp = () => {
    const values = getValues();
    // 这里会自动提示username、password、password_confirmation、is_admin这些字段!
    console.log(values.username);
  };

  // ... 其他表单渲染代码
};

可选:手动指定泛型(特殊场景)

如果有些场景下你需要提前定义表单字段类型,也可以手动传递泛型:

// 提前定义表单字段类型
type SignUpFormFields = {
  username: string;
  password: string;
  password_confirmation: string;
  is_admin?: string;
};

// 手动传递泛型(需对应字段的Schema类型)
const { register, onSubmit, getValues, errors } = useCustomForm<{
  username: yup.StringSchema;
  password: yup.StringSchema;
  password_confirmation: yup.StringSchema;
  is_admin: yup.StringSchema;
}>({
  // ... 字段定义和之前一样
});

不过大多数情况下,自动推断已经足够好用,不需要手动传泛型。

备注:内容来源于stack exchange,提问作者codeman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 11:08:02