[英]Strongly typing the value parameter of the render method of the Controller in React hook form
使用 react 鈎子形式, Controller#render
方法被傳遞了一個包含當前控制值的value
參數。 它的類型為any
,是否可以強類型,例如,如果由 controller 管理的組件要呈現string
,則render
方法的 value 參數應在 value 參數中鍵入為string
。 這是一個沙盒
import { useForm, Controller } from "react-hook-form";
type Person = {
firstName: string;
lastName: string;
};
export default function App() {
const { handleSubmit, control, register } = useForm<Person>({
defaultValues: {
firstName: "John",
lastName: "Smith"
}
});
const onSubmit = (data: Person) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="firstName" ref={register} />
<Controller
control={control}
name="lastName"
// *************************************
// ====> value is typed as `any`, how to type it as the bound enity, i.e. string from Person.lastName?
// *************************************
render={({ onChange, name, value }) => (
<input
name={name}
value={value}
onChange={onChange}
/>
)}
/>
<input type="submit" value="Submit"></input>
</form>
);
}
解決方案 v7
從 v7 開始,與 v6 相比,RHF 對 TypeScript 的支持要好得多。 因此,例如,關於register
方法的重大變化。 如果可能,請更新到此版本。
解決方案 v6
如果您需要使用 v6,RHF 提供的這個小package將使Controller
組件更加類型安全。
運行 RHF 7.18.0 和 Typescript 4.4.4。 Controller
定義似乎已經改變。 找不到輸入 Contoller 的value
和defaultValue
的方法。 我正在嘗試創建一個通用的Select
字段,如下所示,但是當將通用 T 作為第二種類型的 Contoller 傳遞時,ESLint 會抱怨。
import Box from "@mui/material/Box";
import Checkbox from "@mui/material/Checkbox";
import InputLabel from "@mui/material/InputLabel";
import ListItemText from "@mui/material/ListItemText";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectProps } from "@mui/material/Select";
import { Control, Controller, FieldValues } from "react-hook-form";
type UnBox<T> = T extends (infer U)[] ? U : T;
export interface IOptions<T> {
value: T;
displayedLabel: string;
}
type ISelectFieldProps<T extends Array<string | number> | string | number> =
SelectProps<T> & {
name: string;
control: Control;
options: Array<IOptions<T extends Array<string | number> ? UnBox<T> : T>>;
optionsAsCheckBox?: boolean;
};
const SelectField = <T extends Array<string | number> | string | number>({
name,
control,
defaultValue,
label,
options,
optionsAsCheckBox = false,
...rest
}: ISelectFieldProps<T>): JSX.Element => {
return (
<Controller<FieldValues, T> <--error here. Changing T to any fixed, but then value and defaultValue are any and not typeof T...
name={name}
control={control}
defaultValue={defaultValue}
render={({ field: { onChange, onBlur, value } }) => (
<Box>
<InputLabel id={name}>{label}</InputLabel>
<Select
label={label}
onChange={onChange}
value={value}
onBlur={onBlur}
{...rest}
>
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{optionsAsCheckBox && (
<Checkbox checked={value.indexOf(option.value) > -1} />
)}
<ListItemText primary={option.displayedLabel} />{" "}
</MenuItem>
))}
</Select>
</Box>
)}
/>
);
};
export default SelectField;
調用它的例子
<SelectField<Array<string>>
name="ton"
multiple
control={control}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.join(", ")}
defaultValue={[]}
label="Ton"
options={[
{
value: "A",
displayedLabel: "AAAA",
},
{
value: "B",
displayedLabel: "BBBB",
},
{
value: "C",
displayedLabel: "CCCCC",
},
]}
/>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.