You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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>'

核心原因

  1. IForm中profileImgFile定义为File类型,但Yup.mixed()默认未指定具体类型,导致TS无法推断出与IForm匹配的类型。
  2. 代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 13:25:14