React-hook-form类型错误:`addresses.${string}.street`无法赋值给Path<TFieldValues>
React Hook Form中
name属性类型不匹配Path<TFieldValues>的问题解析 问题代码
import React from "react" import { z } from "zod" import { Control, Controller } from "react-hook-form" export const address = z.object({ street: z.string(), }) type FieldValues<TPrefix extends string> = { addresses: { [k in TPrefix]: z.infer<typeof address> } } export type AddressProperties< TFieldValues extends FieldValues<TPrefix>, TPrefix extends string = string, > = { control: Control<TFieldValues> prefix: TPrefix } export function Address<TFieldValues extends FieldValues<TPrefix>, TPrefix extends string>( properties: AddressProperties<TFieldValues>, ) { const { control, prefix} = properties return <Controller control={control} // Type '`addresses.${string}.street`' is not assignable to type 'Path<TFieldValues>' name={`addresses.${prefix}.street`} render={() => <input />} /> }
问题
为什么name属性的类型无法赋值给Path<TFieldValues>?该如何修复这个问题?
原因
- 泛型约束模糊:原代码中
TPrefix仅被约束为string,TypeScript无法确认它就是TFieldValues['addresses']的合法键,因此无法认定addresses.${prefix}.street是Path<TFieldValues>的有效路径。 - 路径类型的精确性要求:
Path<T>是react-hook-form生成的精确字符串字面量联合类型,而模板字符串${string}.street生成的是宽泛的string子类,TypeScript不会自动将宽泛类型收缩为精确的路径联合类型。
修复方案
方案1:优化泛型约束+类型断言
调整泛型参数,让prefix明确关联到TFieldValues['addresses']的键,再用类型断言确认路径合法性:
import React from "react" import { z } from "zod" import { Control, Controller, Path } from "react-hook-form" export const address = z.object({ street: z.string(), }) export type AddressProperties<TFieldValues> = { control: Control<TFieldValues> // 约束prefix是addresses的键且类型为string prefix: keyof TFieldValues['addresses'] & string } // 约束TFieldValues必须包含符合结构的addresses字段 export function Address<TFieldValues extends { addresses: Record<string, z.infer<typeof address>> }>( properties: AddressProperties<TFieldValues>, ) { const { control, prefix} = properties return <Controller control={control} name={`addresses.${prefix}.street` as Path<TFieldValues>} render={() => <input />} /> }
方案2:精确泛型推断(无需断言)
通过定义更明确的类型结构,让TypeScript自动推断合法路径:
import React from "react" import { z } from "zod" import { Control, Controller, Path } from "react-hook-form" export const addressSchema = z.object({ street: z.string(), }) type AddressType = z.infer<typeof addressSchema> // 明确FieldValues的结构要求 type AddressFieldValues = { addresses: Record<string, AddressType> } export type AddressProperties<TFieldValues extends AddressFieldValues> = { control: Control<TFieldValues> prefix: keyof TFieldValues['addresses'] } export function Address<TFieldValues extends AddressFieldValues>( { control, prefix }: AddressProperties<TFieldValues>, ) { const fieldName = `addresses.${prefix}.street` as Path<TFieldValues> return <Controller control={control} name={fieldName} render={() => <input />} /> }
内容的提问来源于stack exchange,提问作者Pavel Perevezencev
相关产品推荐
相关产品推荐

