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

React-Hook-Form:子表单场景下如何正确类型化泛型UseFormRegister

问题原因

你的写法无效,核心是泛型约束精度不够:

  • 你用T extends MacroFormValues作为约束,但MacroFormValues是独立接口,TypeScript没法从这个约束里推断出T的macro属性必然包含Macro的完整结构。虽然逻辑上T继承了MacroFormValues,但编译器无法把Macro的路径信息关联到T的Path<T>类型中。
  • Path<T>要求严格匹配T的合法路径,编译器无法确认'macro.calories'一定属于Path<T>——因为理论上T可以扩展MacroFormValues并修改macro的结构(比如重定义macro为不含calories的类型,尽管这不符合你的预期,但TypeScript会考虑这种可能性)。
解决方案

不用类型断言的话,有两种严谨的实现方式:

方式1:直接约束T包含macro: Macro

把泛型约束从T extends MacroFormValues改成T extends { macro: Macro },直接明确T必须包含符合Macro结构的macro属性,这样编译器能确定'macro.calories'是Path<T>的合法路径:

type Macro = {
  calories: number
}

interface MacroFormProps<T extends { macro: Macro }> {
  register: UseFormRegister<T>;
}

export const MacroForm = <T extends { macro: Macro }>({
  register,
}: MacroFormProps<T>) => {
  return (
      <Input
        label="Calories"
        inputProps={{
          type: 'number',
          ...register('macro.calories'),
        }}
      />
  );
};

方式2:保留MacroFormValues,用交叉类型强化约束

如果需要保留MacroFormValues接口,可以通过交叉类型强制T的macro属性兼容Macro,让编译器正确识别路径:

type Macro = {
  calories: number
}

interface MacroFormValues {
  macro: Macro;
}

interface MacroFormProps<T extends MacroFormValues & { macro: Macro }> {
  register: UseFormRegister<T>;
}

export const MacroForm = <T extends MacroFormValues & { macro: Macro }>({
  register,
}: MacroFormProps<T>) => {
  return (
      <Input
        label="Calories"
        inputProps={{
          type: 'number',
          ...register('macro.calories'),
        }}
      />
  );
};

两种方式的核心都是让编译器明确T的macro属性一定包含calories字段,从而让Path<T>包含'macro.calories',解决类型错误。第一种方式更简洁,优先推荐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:57:19