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

Next.js13+TS环境中React Hook Form的watch/useWatch类型错误排查

Next.js 13 + React Hook Form 7 + TypeScript 中 watch/useWatch 类型不匹配问题

问题背景

使用 Next.js 13、React Hook Form 7 和 TypeScript 开发时,调用 watch 钩子出现参数类型不匹配错误,即使将 tsconfig.json 中的 strict 设置为 false 也无法解决,useWatch 钩子同样存在该问题。

相关代码

watch 示例代码

import React from "react";
import { useForm } from "react-hook-form";

interface IFormInputs {
  name: string;
  showAge: boolean;
  age: number;
}

function App() {
  const {
    register,
    watch,
    formState: { errors },
    handleSubmit,
  } = useForm<IFormInputs>();
  const watchShowAge = watch("showAge", false); // 提供默认值作为第二个参数
  const watchAllFields = watch(); // 不传参数时监听所有字段
  const watchFields = watch(["showAge", "age"]); // 指定监听特定字段

  // watch 的回调版本,需自行在组件卸载时取消订阅
  React.useEffect(() => {
    const subscription = watch((value, { name, type }) => console.log(value, name, type));
    return () => subscription.unsubscribe();
  }, [watch]);

  const onSubmit = (data: IFormInputs) => console.log(data);

  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register("name", { required: true, maxLength: 50 })} />
        <input type="checkbox" {...register("showAge")} />
        {/* 根据选择显示年龄输入框 */}
        {watchShowAge && <input type="number" {...register("age", { min: 50 })} />}
        <input type="submit" />
      </form>
    </>
  );
}

useWatch 示例代码

import * as React from "react";
import { useForm, useWatch, Control } from "react-hook-form";

interface FormInputs {
  firstName: string;
}

function FirstNameWatched({ control }: { control: Control<FormInputs> }) {
  const firstName = useWatch({
    control,
    name: "firstName", // 不传 name 则监听整个表单,或传入数组监听多个字段
    defaultValue: "default" // 渲染前的默认值
  });

  return <p>Watch: {firstName}</p>; // 仅当 firstName 变化时组件重新渲染
}

function App() {
  const { register, control, handleSubmit } = useForm<FormInputs>();

  const onSubmit = (data: FormInputs) => {
    alert(JSON.stringify(data));
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>First Name:</label>
      <input {...register("firstName")} />
      <input type="submit" />
      <FirstNameWatched control={control} />
    </form>
  );
}

错误信息

useWatch 对应的类型错误提示

Argument type {defaultValue: string, name: string, control: Control<FormInputs>} is not assignable to parameter type {defaultValue?: DeepPartialSkipArrayKey<DeepPartial<FormInputs>>, control?: Control<DeepPartial<FormInputs>>, disabled?: boolean, exact?: boolean}

解决方案

这类类型不匹配问题通常由依赖版本不一致、类型推导异常导致,可按以下步骤修复:

  • 统一依赖版本:确保安装的 react-hook-form 版本与官方示例一致,执行命令重新安装稳定版本:

    npm install react-hook-form@7.45.2
    
  • 正确传递 Control 类型:避免手动声明错误的 Control 类型,直接从 useForm 的返回值中推导:

    function FirstNameWatched({ control }: { control: ReturnType<typeof useForm<FormInputs>>["control"] }) {
      const firstName = useWatch({
        control,
        name: "firstName",
        defaultValue: "default"
      });
      return <p>Watch: {firstName}</p>;
    }
    
  • 显式指定泛型参数:调用 useWatch 时显式传入泛型,帮助 TypeScript 正确推导类型:

    const firstName = useWatch<FormInputs, "firstName">({
      control,
      name: "firstName",
      defaultValue: "default"
    });
    
  • 优化 TypeScript 配置:调整 tsconfig.json 中的类型相关配置,确保兼容性:

    {
      "compilerOptions": {
        "strictNullChecks": false,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "module": "ESNext",
        "moduleResolution": "Node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "jsx": "preserve",
        "lib": ["DOM", "DOM.Iterable", "ESNext"]
      }
    }
    
  • 清除缓存重启服务:Next.js 缓存可能导致类型推导异常,执行命令清除缓存后重启开发服务器:

    rm -rf .next node_modules/.cache
    npm run dev
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:52:42