zod
zod copied to clipboard
z.infer<T> infers dynamic fields are required even if required prop is false.
Environment:
- zod v. 3.22.4
- TypeScript v. 4.9.5
I have this props
interface Props {
additional_questions?: Question[]
}
Question is this type
type TextQuestion = {
id: number;
title: string;
type: "text";
value: string;
required?: boolean;
};
The property additional_questions is
[
{
id: 1,
title: "Idade",
value: "",
type: "text",
required: false
}
]
I have this zod form scheme
const formSchema = z.object({
email: z.string().email("E-mail inválido"),
names: z.string().min(1, "Campo obrigatório"),
surnames: z.string().min(1, "Campo obrigatório"),
phonenumber: z.string(),
attendance: z.enum(["yes", "no"], {
required_error: "Precisa de selecionar se aceita ou não o convite.",
}),
message: z.string(),
additional_questions: z.array(
z.object({
id: z.number(),
answer: z.string().min(1),
title: z.string(),
type: z.string(),
required: z.boolean()
})
),
});
and this is the form:
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
names: "",
surnames: "",
phonenumber: "",
attendance: "yes",
message: "",
additional_questions: props.additional_questions
},
});
And this is the render section:
{props.additional_questions && props.additional_questions?.map((question, index) => (
<FormField
key={question.id}
control={form.control}
name={`additional_questions.${question.id}.id`}
render={({ field }) => (
<FormItem>
<FormLabel>{question.title}:</FormLabel>
<FormControl>
{
question.type == "text" ? <Input disabled={loading} {...field} /> :
question.type == "textarea" ? <TextArea rows={5} disabled={loading} {...field} /> :
<div></div>
}
</FormControl>
<FormMessage />
</FormItem>
)}
/>
))}
I don't know why when I try to submit the form all the additional questions are required even if the props.additional_questions has questions with required a false.
Can you help me?
I think you just need to add .optional() to your additional_questions field, like the following.
const formSchema = z.object({
email: z.string().email("E-mail inválido"),
names: z.string().min(1, "Campo obrigatório"),
surnames: z.string().min(1, "Campo obrigatório"),
phonenumber: z.string(),
attendance: z.enum(["yes", "no"], {
required_error: "Precisa de selecionar se aceita ou não o convite.",
}),
message: z.string(),
additional_questions: z.array(
z.object({
id: z.number(),
answer: z.string().min(1),
title: z.string(),
type: z.string(),
required: z.boolean()
})
).optional(),
});
Does that help?
Hi. Thanks for you help, but i've already tried that before and it didn't work as I tought.
Here are some prints for evidence
Also...
I even tried to add .optional() in the z.object() and the component's behaviour was the same.