New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
issue: can't get typescript to accept different schema output using zod #9600
Comments
If I change const formSchema = z.object({
myInput: z.string().transform(Number)
});
type FormSchema = z.infer<typeof formSchema>;
export default function App() {
const { register, handleSubmit } = useForm<FormSchema>({
resolver: zodResolver(formSchema),
defaultValues: {
myInput: 'Hello World' // TS error: myInput must be a number!
}
});
function handleFormSubmit(data: FormSchemaOutput) {}
return (
<form onSubmit={handleSubmit(handleFormSubmit)}>
<input type="text" {...register("myInput")} />
</form>
);
} |
hi, @diego3g thanks for the issue report. I don't think this is possible to support different schema outputs with the current design without breaking the existing type inference. However, I am open to suggestions or potential solutions. The following example. const formSchema = z.object({
myInput: z.string().transform(Number)
}); The transformation occurs runtime inside the Zod resolver and hence returned Here is a current workaround for your use case export default function App() {
const { register, handleSubmit } = useForm<FormSchemaOutput>({
resolver: zodResolver(formSchema),
defaultValues: {
myInput: 0 // use number as defaultValue
}
});
return (
<form onSubmit={handleSubmit(data => data)}>
<input type="text" {...register("myInput", {valueAsNumber: true})} /> // setValueAsNumber to transform within hook form
</form>
);
} |
Hello @bluebill1049, this was just an example, my schema is bigger than that and I can't use the default values using the output schema as these values are used to fill a field array with a lot of options. I think React Hook Form should somehow receive the I can work on a PR with that, just let me know if this is something you think is cool. |
Yea would love to see a PR on this. Thank you in advance. |
First of all, thanks for this awesome library! I'm also hitting this problem recently and found this issue. Here's a Code Sandbox to show a slightly complex type. https://codesandbox.io/s/react-hook-form-zod-type-error-v9w19n I haven't dug into the RHF's code base much, but as @diego3g mentioned, I would love to pass another generic type to the Something like this: useForm<InputSchema, OutputSchema>({
resolver: zodResolver(
inputSchema.transform((v) => ({
categories: v.categories.value
}))
),
defaultValues: {
categories: { value: "category3" }
}
}); |
Figured I'd pop in and share a similar use case with const validationSchema = z.object({
image: z
.custom<FileList>()
.refine((file) => file?.length == 1, 'Image is required.')
.transform(([file]) => file)
.refine((file) => file?.size <= MAX_FILE_SIZE, `Max image size is 10MB.`)
.refine(
(file) => ACCEPTED_IMAGE_TYPES.includes(file?.type),
'Only .jpg, .jpeg, .png and .webp formats are supported.'
),
}); Now lets say you want to preview the image that has been selected before the form is submitted, export function App() {
const form = useForm<ValidationSchema>({
resolver: zodResolver(validationSchema),
});
const imageList = form.watch('image', undefined) as unknown as
| FileList
| undefined;
const imageUrl = useMemo(() => {
const image = imageList?.item(0);
if (image) {
return URL.createObjectURL(image);
}
}, [imageList]);
return (
<form onSubmit={form.handleSubmit(console.log)}>
<div>
<input type="file" {...form.register('image')} />
{imageUrl ? <img src={imageUrl} /> : <ImagePlaceholder />}
</div>
</form>
);
} Thankfully |
Thanks, @Brendonovich for the feedback. I think the new generic we are proposing are transformed result at the runtime, by most of the use cases a single useForm<FieldValues, Context, TransformedFieldValues>(); |
Any thoughts on the following API? it can go alone well with the new "potential" Form component const defaultValues = { test: 'test' };
type FormValues = typeof defaultValues;
type TransformedFormValue = {
test: number;
};
const Test = () => {
const { control } = useForm({
defaultValues: { test: 'test' },
});
return (
<Form<FormValues, TransformedFormValue>
onSubmit={(data) => {
console.log(data); // data.test -> number
}}
control={control} // optional if not using context
>
<input />
</Form>
);
}; |
This comment was marked as off-topic.
This comment was marked as off-topic.
@bluebill1049 That API looks good and would be much appreciated. I would really like to see const testSchema = z.object({
test: z.string().transform(Number),
});
const { handleSubmit } = useForm({
defaultValues: { },
// ^? { test?: string | undefined } | undefined
resolver: zodResolver(testSchema),
});
<form
onSubmit={handleSubmit((payload) => {
// ^? { test: number }
}}
> Currently implementing this like so: const testShema = z.object({
test: z.string().transform(Number),
});
type TestFormFields = z.input<typeof testSchema>;
type TestFormPayload = z.output<typeof testSchema>;
const { handleSubmit } = useForm<TestFormFields>({
defaultValues: { },
// ^? { test?: string | undefined } | undefined
resolver: zodResolver(testSchema),
});
<form
onSubmit={handleSubmit((values: unknown) => {
const data = values as TestFormPayload;
// ^? { test: number }
}}
> |
Version Number
7.38.0
Codesandbox/Expo snack
https://codesandbox.io/s/hidden-cloud-vruf30?file=/src/App.tsx:0-718
Steps to reproduce
Expected behaviour
React Hook Form should automatically infer the output type for the schema sent via the
resolver
property or allow us to set the input and output schema types when usinguseForm
hook.What browsers are you seeing the problem on?
Chrome
Relevant log output
No response
Code of Conduct
The text was updated successfully, but these errors were encountered: