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

如何基于React Hook Form的useFormContext实现输入组件name类型安全

实现基于Form Schema的类型安全输入组件

核心思路

通过泛型将输入组件与表单Schema类型绑定,利用React Hook Form提供的FieldPath类型工具,限制name属性只能是Schema中的合法字段名,同时让register和errors自动适配Schema类型,实现全链路类型安全。

修改步骤与代码实现

1. 导入必要的类型工具

首先导入React Hook Form提供的类型工具,用于约束组件的泛型逻辑:

import { ExclamationCircleIcon } from "@heroicons/react/20/solid";
import React from "react";
import { useFormContext, FieldPath, UseFormReturn } from "react-hook-form";

2. 定义泛型Props与组件

将组件和Props改为泛型结构,绑定表单Schema类型,让name属性只能接收Schema内的合法字段:

// 泛型Props,T代表表单Schema的类型
interface InputProps<T extends object> {
  label: string;
  name: FieldPath<T>; // 仅允许T中的合法字段名
  type?: string;
  placeholder?: string;
}

// 泛型组件,接收表单Schema类型T
export function InputWithValidationError<T extends object>({
  label,
  name,
  type = "text",
  placeholder,
}: InputProps<T>) {
  // 为useFormContext指定类型,确保register和errors与Schema匹配
  const { register, formState: { errors } } = useFormContext<UseFormReturn<T>>();
  
  // errors自动适配Schema类型,无需手动类型断言
  const error = errors[name]?.message;

  return (
    <div>
      <label htmlFor={name}>{label}</label>
      <input
        id={name}
        type={type}
        placeholder={placeholder}
        {...register(name)} // 此时register仅接受T中的合法字段
      />
      {error && <p className="text-red-500 flex items-center gap-1">
        <ExclamationCircleIcon className="w-4 h-4" />
        {error}
      </p>}
    </div>
  );
}

3. 表单上下文的类型传递

在使用FormProvider时,传入带有明确Schema类型的useForm返回值,子组件会自动继承该类型:

import { useForm, FormProvider } from "react-hook-form";

// 定义表单Schema类型
type LoginFormSchema = {
  email: string;
  password: string;
};

export default function LoginPage() {
  // 传入Schema类型初始化表单方法
  const methods = useForm<LoginFormSchema>();

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit((data) => console.log(data))}>
        {/* TypeScript会自动提示"email"和"password" */}
        <InputWithValidationError label="Email" name="email" />
        <InputWithValidationError label="Password" name="password" />
        {/* ❌ 输入"username"会直接触发TypeScript错误 */}
        {/* <InputWithValidationError label="Username" name="username" /> */}
        <button type="submit">登录</button>
      </form>
    </FormProvider>
  );
}

关键说明

  • FieldPath<T>:React Hook Form提供的类型工具,提取T中所有合法的字段路径(支持嵌套字段,如user.email)
  • 泛型组件:通过泛型绑定表单Schema,让组件可以复用在不同Schema的表单场景中
  • 类型化上下文:useFormContext<UseFormReturn<T>>确保register和errors的类型与Schema完全匹配,避免冗余的类型断言

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:10:16