React-Hook-Form中defaultValues遇null类型不兼容警告求助
TanStack Query数据作为React-Hook-Form默认值的类型错误解决
问题情况
使用TanStack Query从数据库拉取数据,作为React-Hook-Form的defaultValues用于编辑页面时,尽管数据库返回完整的表单数据,但仍收到类型错误警告,hover查看defaultValues时无法定位null | undefined的来源。
警告信息
Type '{ id: string; title: string; email: string; fullName: string; contactPerson: string; department: string; dateOfEvent: string; startingTime: string; endingTime: string; purpose: string; doesHaveDryRun: string; ... 11 more ...; updatedAt: Date; } | null | undefined' is not assignable to type 'AsyncDefaultValues<{ title: string; email: string; fullName: string; contactPerson: string; department: string; dateOfEvent: string; startingTime: string; endingTime: string; purpose: string; doesHaveDryRun: "yes" | "no"; ... 8 more ...; cameraSetup?: string | undefined; }> | { ...; } | undefined'. Type 'null' is not assignable to type 'AsyncDefaultValues<{ title: string; email: string; fullName: string; contactPerson: string; department: string; dateOfEvent: string; startingTime: string; endingTime: string; purpose: string; doesHaveDryRun: "yes" | "no"; ... 8 more ...; cameraSetup?: string | undefined; }> | { ...; } | undefined'.
数据库返回数据
| id | title | fullName | contactPerson | department | dateOfEvent | startingTime | endingTime | purpose | doesHaveDryRun | dryRunDate | dryRunStart | dryRunEnd | doesHaveTCETAssitance | tcetOtherAssitance | meetingTypeOption | meetingTypeServices | meetingTypeServiceLink | cameraSetup | createdAt | updatedAt | status | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| clw4bmve20007o97k025zny6i | test6 | test6@gmail.com | test6 | test6 | test6 | 5/14/2024 | 8:00 AM | 12:00 PM | meeting | yes | 5/15/2024 | 8:00 AM | 10:00 AM | tcet,others | test6 | meeting | meeting_attendees,meeting_waiting | sdsasd | twoCamera | 2024-05-13 02:04:48.362 | 2024-05-13 02:04:48.362 | PENDING |
Zod Schema代码
const formSchemaData = z.object({ title: z.string().min(2, { message: "title must be at least 2 characters.", }), email: z.string().min(2, { message: "email must be at least 2 characters.", }).email(), fullName: z.string().min(2, { message: "The person who requested the event", }), contactPerson: z.string().min(2, { message: "Contact Person / Event Handler" }), department: z.string().min(2, { message: "department must be at least 2 characters.", }), dateOfEvent: z.string(), // Assuming dateOfEvent is a string in the desired format startingTime: z.string().min(2, { message: "staring time must be set.", }), endingTime: z.string().min(2, { message: "ending time must be set.", }), purpose: z.string().min(2,{ message: "Please choose a purpose of the meeting.", }), doesHaveDryRun: z.enum(["yes", "no"], { required_error: "Please select if yes or not" }), dryRunDate: z.string().optional(), dryRunStart: z.string().optional(), dryRunEnd: z.string().optional(), doesHaveTCETAssitance: z.array(z.string()).refine((value) => value.some((item) => item), { message: 'Please select at lease on the option' }), tcetOtherAssitance: z.string().optional(), meetingTypeOption: z.enum(['meeting','webinar','hybrid','documentation', 'training']), meetingTypeServices: z.array(z.string()).refine((value) => value.some((item) => item), { message: 'Please select at lease on the option' }), meetingTypeServiceLink: z.string().optional(), cameraSetup: z.string().optional(), }) export type Events = z.infer<typeof formSchemaData>
获取数据并设置defaultValues的代码
const { id } = useParams(); const { data: eventData, error, isFetching } = useQuery({ queryKey: ["id", id], queryFn: async () => { const res = await getDataById(id) return res }, }); const form = useForm<Events>({ resolver: zodResolver(formSchemaData), defaultValues: eventData });
问题原因
- TanStack Query数据类型不确定性:
useQuery返回的data默认类型为T | undefined,如果getDataById可能返回null,类型会变成T | null | undefined。而React-Hook-Form的defaultValues不接受null类型,导致类型不匹配。 - 数据库数据与Zod Schema类型不匹配:
- 数据库返回的
doesHaveDryRun是普通字符串,但Zod定义的是"yes" | "no"枚举类型,类型不兼容。 doesHaveTCETAssitance和meetingTypeServices在数据库中是逗号分隔的字符串,但Zod定义的是字符串数组,类型不匹配。
- 数据库返回的
解决方案
1. 消除TanStack Query数据的空值类型
方法一:条件渲染确保数据加载完成
在渲染表单前先判断数据是否存在,避免传递null/undefined给defaultValues:
if (!eventData || isFetching) { return <div>Loading...</div>; } const form = useForm<Events>({ resolver: zodResolver(formSchemaData), defaultValues: eventData });
方法二:明确指定useQuery的返回类型
确保useQuery和getDataById的返回类型为Events,消除空值歧义:
// 先确保getDataById的返回类型是Promise<Events> const { data: eventData, error, isFetching } = useQuery<Events>({ queryKey: ["id", id], queryFn: async () => { const res = await getDataById(id); return res; }, }); // 或用空值合并提供默认值(仅临时方案,推荐条件渲染) const form = useForm<Events>({ resolver: zodResolver(formSchemaData), defaultValues: eventData ?? {} as Events });
2. 修正数据库数据与Zod Schema的类型差异
在queryFn中转换数据格式,让返回值匹配Zod定义的类型:
const { data: eventData, error, isFetching } = useQuery<Events>({ queryKey: ["id", id], queryFn: async () => { const res = await getDataById(id); // 转换枚举类型 const doesHaveDryRun = res.doesHaveDryRun as "yes" | "no"; // 转换逗号分隔字符串为数组 const doesHaveTCETAssitance = res.doesHaveTCETAssitance.split(','); const meetingTypeServices = res.meetingTypeServices.split(','); return { ...res, doesHaveDryRun, doesHaveTCETAssitance, meetingTypeServices } as Events; }, });
内容的提问来源于stack exchange,提问作者Stykgwar
相关产品推荐
相关产品推荐

