React Hook Form 中 onSubmit 类型错误的解决方案

本文详解 react hook form + typescript 下 `onsubmit` 函数触发 eslint `no-misused-promises` 报错的原因及正确修复方式,重点说明为何需显式返回 promise 以及如何保持类型安全与逻辑简洁。

在使用 React Hook Form 的 handleSubmit 时,其内部会对传入的 onSubmit 回调进行类型校验。SubmitHandler 类型定义要求该函数必须返回 Promise 或 void,但关键在于:handleSubmit 实际会将 onSubmit 包装为一个事件处理器,并期望它能兼容异步流程(例如表单提交后可能触发 API 调用)。当 ESLint 启用 @typescript-eslint/no-misused-promises 规则时,它会检测到「被赋值给需要 void 返回值的位置的函数却声明了 async 或隐式返回 Promise」——而更常见的情况是:你写的 onSubmit 是同步函数(无 return),但 handleSubmit 的类型签名强制要求它可被当作 Promise 处理,导致类型系统推断冲突。

根本原因在于:SubmitHandler 的完整类型等价于

(data: T, event?: React.BaseSyntheticEvent) => void | Promise

因此,即使你的逻辑完全同步,也必须显式满足该联合类型。最稳妥、零歧义的做法是让 onSubmit 显式返回 Promise

✅ 正确写法(推荐):

const onSubmit: SubmitHandler = (data, event) => {
  event?.preventDefault();
  const { searchQuery } = data;
  dispatch(setSearchQuery(searchQuery));
  return Promise.resolve(); // ✅ 明确返回 Promise
};

或如答案中所示,使用构造器(语义更清晰):

const onSubmit: SubmitHandler = (data, event) => {
  return new Promise((resolve) => {
    event?.preventDefault();
    const { searchQuery } = data;
    dispatch(setSearchQuery(searchQuery));
    resolve(); // ✅ 同步操作后立即 resolve
  });
};

⚠️ 注意事项:

  • 不要写 async onSubmit(...) 并仅执行同步逻辑,因为 async 函数总会返回 Promise,易引发类型不匹配或不必要的 await 开销;
  • event?.preventDefault() 在 handleSubmit 封装下通常已自动处理(React Hook Form 默认调用 preventDefault),除非你手动触发表单提交,否则可省略;若保留,建议确保 event 存在性;
  • 若后续需加入异步操作(如 API 请求),直接 await 并 return 即可,类型依然兼容:
    const onSubmit: SubmitHandler = async (data) => {
      const { searchQuery } = data;
      dispatch(setSearchQuery(searchQuery));
      await api.search(searchQuery); // ✅ 自动返回 Promise
    };

总结:该错误本质是 TypeScript 类型系统与 ESLint 规则对“可承诺行为”的严格校验。只需确保 onSubmit 显式返回 Promise(哪怕内容同步),即可彻底消除报错,同时保持代码健壮性与未来扩展性。