Playground with the code
I’m using react-hook-form
and Zod
for form validation in my TypeScript application. I have a form component that accepts props with generic types. However, I’m getting a TypeScript error when trying to specify default values for defaultValues
in useForm
. By the way, I have the same problem even with a regular interface, not only with Zod
schema.
const withEditableItemCard = <
Schema extends BaseItemFormSchema,
SchemaShape extends z.infer<Schema> = z.infer<Schema>
>(
FormFieldsComponent: React.FC<{ readOnly?: boolean }>,
{ title, formSchema, onSubmit }: FormControlsProps<Schema>
) => {
return ({ initialData, onClose }: EditableFormProps<Schema>) => {
const { id } = useParams();
const dispatch = useAppDispatch();
const formMethods = useForm<SchemaShape>({
defaultValues: {
id,
...initialData
},
resolver: zodResolver(formSchema),
});
const handleSubmit = formMethods.handleSubmit(async (values) => {
await dispatch(onSubmit(values));
const checkInferring = values.name;
// ^?
onClose();
});
return (
<></>
);
};
};
I’m getting the following TypeScript error:
(property) defaultValues?: AsyncDefaultValues<SchemaShape> | DefaultValues<SchemaShape> | undefined
Type
{ id: string | undefined; name?: string | undefined; }' is not assignable to type 'AsyncDefaultValues<SchemaShape> | DefaultValues<SchemaShape> | undefined'.
Type '{ id: string | undefined; name?: string | undefined; }' is not assignable to type 'DefaultValues<SchemaShape>'.(2322)
I’ve tried using type assertions, but I want to avoid using type assertions as they are not considered good practice and can lead to type safety issues.
How can I correctly specify the default values for defaultValues
in useForm
without using type assertions and ensure proper typing based on the generic SchemaShape
type?
Here are the relevant type definitions:
export const baseItemFormSchema = z.object({
id: z.string(),
name: z.string(),
});
export type BaseItemFormValues = z.infer<typeof baseItemFormSchema>;
export type BaseItemFormSchema = typeof baseItemFormSchema;
interface EditableFormProps<
Schema extends BaseItemFormSchema,
SchemaShape extends z.infer<Schema> = z.infer<Schema>
> {
initialData?: DefaultValues<SchemaShape>;
onClose: () => void;
header: React.ReactElement;
}
interface FormControlsProps<
Schema extends BaseItemFormSchema,
SchemaShape extends z.infer<Schema> = z.infer<Schema>
> {
title: string;
formSchema: Schema;
onSubmit: (values: SchemaShape) => (dispatch: AppDispatch) => Promise<void>;
}
One interesting observation is that the autocomplete for defaultValues
properties works as expected, and the types are correctly inferred within the handleSubmit
function, without the DeepPartial
utility type. This suggests that the issue might be specific to the defaultValues
prop and not a general typing problem.