如何为自定义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, }; };
关键改动说明
- 泛型约束:用
<Shape extends yup.ObjectShape>确保传入的参数是符合要求的Yup字段定义对象,每个属性都是一个Yup Schema(比如yup.string())。 - 自动推断类型:通过
yup.InferType<typeof formSchema>从创建好的Schema里自动提取出表单字段的类型(比如{ username: string; password: string; ... }),这样useForm就能拿到准确的类型信息。 - 无需手动传泛型: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
相关产品推荐
相关产品推荐

