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
相关产品推荐
相关产品推荐

