我们有react-hook-form + zod + React-query。
如果我不提供可选的默认值,如何使用 TypeScript 键入值以使其捕获错误?
https://codesandbox.io/p/sandbox/react-form-form-question-hwvq7y
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { useQuery } from "@tanstack/react-query";
function App() {
const { data: formValuesFromApi } = useQuery({
queryKey: ["query key"],
queryFn: async () => {
await new Promise((resolve) => {
setTimeout(() => resolve("done"), 1000);
});
return {
name: "John",
};
},
});
const schema = z.object({
name: z.string(),
});
type FormValues = z.infer<typeof schema>;
const methods = useForm<FormValues>({
resolver: zodResolver(schema),
values: formValuesFromApi,
defaultValues: {
// name: "", // NO DEFAULT VALUE
},
});
const onSubmit = (data: FormValues) => {
console.log(data);
};
const formValues = methods.getValues();
// ERROR!
// TS thinks that type of formValues.name is string
const nameChars = formValues.name.split("");
console.log("nameChars", nameChars);
return (
<form onSubmit={methods.handleSubmit(onSubmit)}>
<input {...methods.register("name")} />
<input type="submit" />
</form>
);
}
export default App;
我尝试在谷歌上搜索如何正确输入此类场景的方法。
defaultValues
的类型应与您传递给 useForm
的通用类型匹配。事实上,如果您不传入泛型类型,则 defaultValues
会用作表单数据类型。
const form = useForm({
defaultValues: {
a: 1
}
})
// mouse over `useForm` here to see this type:
// useForm<{ a: number; }, any, undefined>(props?: Partial<{ ...
注意如何
{ a: number; }
。是您尝试传入的泛型类型 FormValues
。
我通常做的是将默认值分解为它们自己的函数,当表单有很多字段时,这非常好。
function getFormDefaults(): FormValues {
return {
name: ''
}
}
(或者如果制作该对象不知何故很昂贵,则将其作为
useMemo
的钩子)
当您希望此表单处理创建和更新时,这也可以很好地扩展:
function getFormDefaults(person?: Person | null): FormValues {
return {
name: person?.name ?? ''
}
}
然后
useForm
调用看起来像:
const methods = useForm({
resolver: zodResolver(schema),
values: formValuesFromApi,
defaultValues: getFormDefaults(),
});
这很好,因为
getFormDefaults
具有表单数据的返回类型,如果默认值不符合该类型,打字稿就会对你大喊大叫。并且 useForm
将选择该类型,然后您的所有字段也将是正确的类型。