如何用TypeScript结合Yup验证文件上传并解决类型报错问题
解决Yup验证Schema与TypeScript类型不匹配问题
问题描述
需要将profileImgFile设为必填项,且要求validationSchema具备TypeScript类型支持。当前验证功能正常,但TypeScript报错:
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>'
核心原因
IForm中profileImgFile定义为File类型,但Yup.mixed()默认未指定具体类型,导致TS无法推断出与IForm匹配的类型。- 代码中
onChange传递的是FileList而非单个File,与IForm的类型定义不一致,进一步加剧类型不匹配。
解决方案
步骤1:修正表单值的传递
将input的onChange事件中传递的FileList改为单个File,匹配IForm的类型定义:
<Controller name="profileImgFile" control={control} render={({ field }) => ( <input ref={fileInputRef} type="file" id="avatar" onChange={(val) => { // 取第一个选中的文件,对应IForm的File类型 field?.onChange(val?.target?.files?.[0]); }} name="profileImgFile" accept="image/png, image/jpeg" /> )} />
步骤2:为Yup Schema指定明确类型
在Yup.mixed()中指定泛型为File,并添加验证确保值是合法的File对象:
const validationSchema: Yup.SchemaOf<IForm> = Yup.object().shape({ name: Yup.string().required("Required"), description: Yup.string().required("Required"), profileImgFile: Yup.mixed<File>() .required("Required") .test("is-valid-file", "请选择有效文件", (value) => { return value instanceof File; }) });
可选简化方案
如果不需要额外的文件合法性检查,也可以直接用typeError确保类型匹配:
profileImgFile: Yup.mixed<File>() .required("Required") .typeError("必须选择一个文件")
完整修正代码
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<File>() .required("Required") .test("is-file", "请选择有效文件", (val) => val instanceof File) }); 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?.[0]); }} name="profileImgFile" accept="image/png, image/jpeg" /> )} />
内容的提问来源于stack exchange,提问作者Arnas Dičkus
相关产品推荐
相关产品推荐

