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

React Hook Form在TypeScript中出现FieldError无required属性错误

React Hook Form迁移到TypeScript后类型错误问题解析

问题描述

在React.js页面使用React Hook Form做表单验证一切正常,但迁移到TypeScript页面后出现以下错误:

Property 'required' does not exist on type 'FieldError | Merge<FieldError, FieldErrorsImpl> | MultipleFieldErrors'.
Property 'required' does not exist on type 'FieldError'.

相关代码如下:

import { useForm } from "react-hook-form";
import { GiInfo } from "react-icons/gi";

export default function TestPage() {
    const {register,getValues,formState: { errors },handleSubmit} = useForm({criteriaMode: "all",mode: "onChange"});
    const onSubmit = (data) => console.log(data);
  return (
   
   
<div className='container mt-5 Validation_From'> 
<div className='bg-light rounded border border-2 p-3 mt-5'> 
<form onSubmit={handleSubmit(onSubmit)}>
    <div className='row align-items-center'>
    <div className="col-md-3 position-relative mb-2">

    <label className="form-label">Name</label>
    <input
          className="form-control"
            type="text"
            id="name"
            autoComplete="off" 
            {...register("name", {
              required: true,
              minLength: 2,
              
            })}
          />

    {errors?.name?.types?.required && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
    {errors?.name?.types?.minLength && <div className='c_validation'><GiInfo/>Name minLength 2 </div>}


    </div>

    <div className="col-md-3 position-relative mb-2">

    <label className="form-label">Email</label>
    <input
          className="form-control"
            type="text"
            id="email"
            autoComplete="off" 
            {...register("email", {
              required: true,
              pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i
            })}
          />


    {errors?.email?.types?.required && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
    {errors?.email?.types?.pattern && <div className='c_validation'><GiInfo/> Invalid email address </div>}


    </div>

      <div className="col-md-3 position-relative mb-2">

    <label className="form-label">Password</label>
    <input
          className="form-control"
            type="password"
            autoComplete="off" 
            id="password"

            {...register("password", {
              required: true,
              minLength: 10,
              pattern: /\d+/gi
            })}
          />

    {errors?.password?.types?.required && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
    {errors?.password?.types?.minLength && <div className='c_validation'><GiInfo/> Password minLength 10 </div>}
    {errors?.password?.types?.pattern && <div className='c_validation'><GiInfo/> Password number only </div>}

      </div>

      <div className="col-md-3 position-relative mb-2">

      <label className="form-label">Confirm Password</label>
    <input
          className="form-control"
            type="password"
            autoComplete="off"  
            id="conpassword"

            {...register("conpassword", {
              required: true,
      
              validate: (value) =>
                value === getValues("password")
            })}

          />


              
    {errors?.conpassword?.types?.required && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
    {errors.conpassword && errors.conpassword.type === "validate" && <div className='c_validation'><GiInfo/>Passwords do not match</div>}

      </div>
      
      <div className="col-md-12 position-relative mb-2 text-end">
           <button className="btn btn-primary rounded mt-4">Submit</button>
      </div>
   

      </div>
  </form>
  </div>
</div>


  )
}

问题原因

  1. TypeScript强类型约束:React Hook Form在TypeScript中对错误对象的类型定义与JavaScript环境不同。FieldError类型并没有types属性,你之前在JS中使用的errors?.name?.types?.required写法属于动态类型的宽松用法,在TS的强类型检查下会报错。
  2. 缺少表单数据类型定义:你没有给useForm指定表单数据的泛型类型,导致TypeScript无法正确推断errors对象的结构,无法识别required这类验证规则对应的错误标识。

修复方案

1. 定义表单数据类型接口

先声明表单字段对应的TypeScript接口,让useForm能准确推断错误结构:

interface FormData {
  name: string;
  email: string;
  password: string;
  conpassword: string;
}

2. 给useForm指定泛型

初始化useForm时传入上述接口,明确表单数据的类型:

const { register, getValues, formState: { errors }, handleSubmit } = useForm<FormData>({
  criteriaMode: "all",
  mode: "onChange"
});

3. 修改错误判断逻辑

React Hook Form在TS中推荐通过error.type字段判断错误类型,替代原来的types属性写法:

  • 原写法:errors?.name?.types?.required
  • 新写法:errors?.name?.type === 'required'

同理,所有错误判断都需要调整为这种形式,比如:

// 验证必填项
{errors?.name?.type === 'required' && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
// 验证最小长度
{errors?.name?.type === 'minLength' && <div className='c_validation'><GiInfo/>Name minLength 2 </div>}
// 验证邮箱格式
{errors?.email?.type === 'pattern' && <div className='c_validation'><GiInfo/> Invalid email address </div>}

完整修复后的代码

import { useForm } from "react-hook-form";
import { GiInfo } from "react-icons/gi";

interface FormData {
  name: string;
  email: string;
  password: string;
  conpassword: string;
}

export default function TestPage() {
  const { register, getValues, formState: { errors }, handleSubmit } = useForm<FormData>({
    criteriaMode: "all",
    mode: "onChange"
  });
  
  const onSubmit = (data: FormData) => console.log(data);

  return (
    <div className='container mt-5 Validation_From'> 
      <div className='bg-light rounded border border-2 p-3 mt-5'> 
        <form onSubmit={handleSubmit(onSubmit)}>
          <div className='row align-items-center'>
            <div className="col-md-3 position-relative mb-2">
              <label className="form-label">Name</label>
              <input
                className="form-control"
                type="text"
                id="name"
                autoComplete="off" 
                {...register("name", {
                  required: true,
                  minLength: 2,
                })}
              />
              {errors?.name?.type === 'required' && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
              {errors?.name?.type === 'minLength' && <div className='c_validation'><GiInfo/>Name minLength 2 </div>}
            </div>

            <div className="col-md-3 position-relative mb-2">
              <label className="form-label">Email</label>
              <input
                className="form-control"
                type="text"
                id="email"
                autoComplete="off" 
                {...register("email", {
                  required: true,
                  pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i
                })}
              />
              {errors?.email?.type === 'required' && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
              {errors?.email?.type === 'pattern' && <div className='c_validation'><GiInfo/> Invalid email address </div>}
            </div>

            <div className="col-md-3 position-relative mb-2">
              <label className="form-label">Password</label>
              <input
                className="form-control"
                type="password"
                autoComplete="off" 
                id="password"
                {...register("password", {
                  required: true,
                  minLength: 10,
                  pattern: /\d+/gi
                })}
              />
              {errors?.password?.type === 'required' && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
              {errors?.password?.type === 'minLength' && <div className='c_validation'><GiInfo/> Password minLength 10 </div>}
              {errors?.password?.type === 'pattern' && <div className='c_validation'><GiInfo/> Password must contain a number </div>}
            </div>

            <div className="col-md-3 position-relative mb-2">
              <label className="form-label">Confirm Password</label>
              <input
                className="form-control"
                type="password"
                autoComplete="off"  
                id="conpassword"
                {...register("conpassword", {
                  required: true,
                  validate: (value) => value === getValues("password")
                })}
              />
              {errors?.conpassword?.type === 'required' && <div className='c_validation'><GiInfo/> Please fill out this field. </div>}
              {errors?.conpassword?.type === 'validate' && <div className='c_validation'><GiInfo/>Passwords do not match</div>}
            </div>
            
            <div className="col-md-12 position-relative mb-2 text-end">
              <button className="btn btn-primary rounded mt-4">Submit</button>
            </div>
          </div>
        </form>
      </div>
    </div>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:20:09