解释
我正在使用react-hook-form中的FormProvider创建一个动态输入表单。
const formMethods = useForm<TSongFormData>();
return (
<FormProvider {...formMethods}>
<SongInputForm />
</FormProvider>
)
在SongInputForm
组件中,我有我的实际表单,它将包含我为每个input elements
创建的输入组件,如input
teaxtarea
等...
const SongForm = () => {
const { handleSubmit } = useFormContext<TSongFormData>();
return (
<form
onSubmit={handleSubmit((data) => console.log("data", data))}
>
<InputElement label="Song Name" name="name" />
<InputElement label="Author" name="author" />
<input type="submit" />
</form>
);
};
}
InputElement
c组件将接收input
元素本身的所有props
,并且name
属性将是表单数据的所有键的联合类型TSongFormDataKey
。
interface ITextInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
name: TSongFormDataKey;
}
const InputElement = ({ name, label, ...restProps }: ITextInputProps) => {
const { register } = useFormContext<TSongFormData>();
return (
<div>
<label htmlFor={name}>{label}</label>
<input id={name} {...restProps} {...register(name)} />
</div>
);
};
问题
到目前为止,我已经在InputElement
组件中硬编码了TSongFormData
和TSongFormDataKey
类型。但是,我如何将TSongFormData
和TSongFormDataKey
类型作为泛型传递给InputElement
组件,以便使其成为动态的,并在传递给它的属性类型上具有更大的灵活性呢?
我要找的是这样的东西:
interface ITextInputProps<T> extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
name: T;
}
const InputElement = <T,K>({ name, label, ...restProps }: ITextInputProps<T>) => {
const { register } = useFormContext<K>();
return (
<div>
<label htmlFor={name}>{label}</label>
<input id={name} {...restProps} {...register(name)} />
</div>
);
};
其中T
将是TSongFormData
且K
将是TSongFormDataKey
。
我已经创建了一个codesandbox,如果有人想玩它:https://codesandbox.io/s/elastic-sanne-uz3ei8
我是打字脚本的新手,试图让我的头围绕泛型,但发现它很难。
任何帮助将不胜感激。谢谢
1条答案
按热度按时间ztigrdn81#
可以将
ITextInputProps
类型和InputElement
名称设置为泛型。对于name
,我们可以使用useFormContext
中的Path
泛型类型。keyof T
也可以使用,除了register
需要Path<T>
,而Path<T>
将包含keyof T
。而Path
仍然具有未解析类型参数(例如T
),则类型脚本将无法遵循该关系。示例化组件时,必须显式指定参数:
<InputElement<TSongFormData> label="Song Name" name="name" />
个您还可以使用较新版本的TS中的示例化表达式为特定类型创建输入字段的专用版本:
综合起来,我们得到:
Playground链接