Reputation: 677
I need for my profileImgFile to be required and I want types in my validationSchema. Currently validation works as expected however typescript doesn't like validationSchema.
Error itself: Type 'ObjectSchema<Assign<ObjectShape, { name: RequiredStringSchema<string | undefined, AnyObject>; description: RequiredStringSchema<string | undefined, AnyObject>; profileImgFile: MixedSchema<...>; }>, AnyObject, TypeOfShape<...>, AssertsShape<...>>' is not assignable to type 'ObjectSchemaOf<IForm, never>'.
From what I read in documentation common consensus is to use yup mixed. Another solution is to use Yup.object() but than you have to deal with file properties.
profileImgFile: Yup.mixed().required("Required")
// Another possible solution
profileImgFile: Yup.object({
// somehow spread all files Properties, or FileList properties.
}).required("Required")
Anyways here's working example code-sandbox
interface IForm {
name: string;
description: string;
profileImgFile: File;
}
const validationSchema: Yup.SchemaOf<IForm> = Yup.object().shape({
name: Yup.string().required("Required"),
description: Yup.string().required("Required"),
profileImgFile: Yup.mixed().required("Required")
});
const {
register,
handleSubmit,
control,
reset,
formState: { errors }
} = useForm<IForm>({
resolver: yupResolver(validationSchema)
});
<Controller
name="profileImgFile"
control={control}
render={({ field }) => (
<input
ref={fileInputRef}
type="file"
id="avatar"
onChange={(val) => {
field?.onChange(val?.target?.files);
}}
name="profileImgFile"
accept="image/png, image/jpeg"
/>
)}
/>
Upvotes: 2
Views: 6076
Reputation: 384
Another solution is simply to put the type File after mixed , this way you don't need to type all the yup schema :
document: Yup.mixed<File>() 👈
.required()
.test('fileSize', i18n.t('medical.form.max.size'), (value) => {
console.log('*******', value);
if (!value) {
return true;
}
return value.size < 1000000;
}),
Upvotes: 2
Reputation: 10939
If we start with a basic file input, it will bind with a FileList
instance.
<Form.Group
controlId="profileImgFile">
<Form.Control
{...register("profileImgFile")}
type="file"/>
<Form.Control.Feedback type="invalid">{errors.profileImgFile?.message}</Form.Control.Feedback>
</Form.Group>
With this approach, profileImgFile
has to be declared as FileList
like shown below in IForm
. I'm aware of that you want just a single file, but it should be fairly simple to deal with that downstream in your code.
interface IForm {
name: string;
description: string;
profileImgFile: FileList;
}
After testing a lot of other approaches, I landed on a Yup.mixed().test()
approach in my app like shown below. You can extend the .test()
chain with other file checks (file size etc).
const validationSchema: Yup.SchemaOf<IForm> = Yup.object().shape({
name: Yup.string().required("Required"),
description: Yup.string().required("Required"),
profileImgFile: Yup.mixed().test(
"required",
"Please select a file",
(files: FileList) => files?.length > 0)
});
Upvotes: 1