React Hook Form 的字段路径类型
这篇记录 2022 年读 react-hook-form 类型源码时关注的两个类型:FieldPath 约束字段路径,FieldPathValue 获取路径对应的值类型。类似的路径构造方法也可以用来理解 i18n 的 key 类型。
什么是 FieldPath ?
FieldPath 是一个泛型类型,它接受一个 TFieldValues 类型作为参数,表示对象中所有字段的路径。FieldPath 的返回值是一个联合类型,表示表单中某个字段或者嵌套字段的路径,用点号分隔。例如,如果我们有一个表单数据对象如下:
interface FormValues {
name: string
address: {
city: string
country: string
}
tuple: [number, string]
array: string[]
}
那么,FieldPath<FormValues> 的可能值有:
- “name”
- “address”
- “tuple”
- “array”
- “address.city”
- “address.country”
- “tuple.0”
- “tuple.1”
- `array.${number}`
这些路径可以用于描述 useController、useWatch、setValue 等 API 操作的字段。字段名写错,或嵌套路径不存在时,就能在类型检查阶段发现。
FieldPath 的构造过程

什么是 FieldPathValue?
FieldPathValue 也是一个泛型类型,它接受两个参数:TFieldValues 和 TFieldPath。TFieldValues 表示表单中所有字段的值的类型,TFieldPath 表示某个字段或者嵌套字段的路径。结果表示 TFieldPath 对应字段的值类型。例如,如果我们还是使用上面的 FormValues 类型,那么:
FieldPathValue<FormValues, "name">的返回值是stringFieldPathValue<FormValues, "address">的返回值是{ city: string; country: string; }FieldPathValue<FormValues, "address.city">的返回值是stringFieldPathValue<FormValues, "tuple.0">的返回值是numberFieldPathValue<FormValues, "array">的返回值是string[]
重点是把字段路径和字段值联系起来。例如 tuple.0 对应 number,而 address 对应整个地址对象。
FieldPathValue 的构造过程


读图里的类型定义,可以按路径拆分来理解:
P先受T的Path或ArrayPath约束。外层的T extends any不能按“排除非 any 类型”理解;这里先沿着路径拆分分支往下看。- 若
P能拆成K.R,先判断K是否为T的键,再对T[K]和剩余路径R递归调用PathValue。 - 若
K匹配${ArrayKey},则走数组索引分支,继续判断T是否为数组。 - 若
P不能继续按点号拆分,先判断它是不是T的键,是则得到T[P]。 - 否则检查它是不是数组索引字符串;匹配数组时取得元素类型,不匹配则得到
never。
这两个类型把字符串路径变成了对象结构上的约束。构造路径时用到泛型、条件类型和字符串模板字面量;取值时则沿着路径递归查找。以后读类似的类型定义,可以先看它在处理“路径生成”还是“路径取值”。