React表单验证Schema类型不兼容:如何解决TypeScript报错?
问题场景
定义的FORM接口:
interface FORM<P> { onSubmit: (d: P) => void; schema?: yup.SchemaOf<P>; }
onSubmit函数:
const onSubmit = (d: { firstName: string; lastName: string }) => { console.log(d); };
Yup schema定义:
const schema = yup.object({ firstName: yup.string().required('name'), lastName: yup.string(), });
传入Test组件时:
<Test onSubmit={onSubmit} schema={schema} >
出现TypeScript错误:
TS2322: Type 'OptionalObjectSchema<{ firstName: RequiredStringSchema<string | undefined, AnyObject>; lastName: StringSchema<string | undefined, AnyObject, string | undefined>; }, AnyObject, TypeOfShape<...>>' is not assignable to type 'ObjectSchema<{ firstName: BaseSchema<Maybe
, AnyObject, string>; lastName: BaseSchema<Maybe , AnyObject, string>; }, AnyObject, TypeOfShape<...>, AssertsShape<...>>'.
The types of 'fields.lastName.__outputType' are incompatible between these types.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
错误原因
核心矛盾是类型不匹配:
- onSubmit的参数要求
lastName为必填string - 但schema中
lastName仅声明为yup.string(),未添加.required()约束,Yup推导的输出类型里lastName是string | undefined - 两者类型冲突,触发TypeScript检查报错
解决方法
方法1:让schema与onSubmit参数严格匹配
根据业务需求二选一:
情况A:允许lastName为可选值
修改onSubmit的参数类型,对齐schema的输出:
const onSubmit = (d: { firstName: string; lastName?: string }) => { console.log(d); };
情况B:要求lastName为必填值
给schema的lastName添加必填约束:
const schema = yup.object({ firstName: yup.string().required('name'), lastName: yup.string().required('last name is required'), });
方法2:显式指定FORM接口的泛型参数
在使用Test组件时,明确声明泛型类型,引导TypeScript正确匹配:
// 允许lastName可选的场景 <Test<{ firstName: string; lastName?: string }> onSubmit={onSubmit} schema={schema} > // 要求lastName必填的场景(需同步修改schema添加.required()) <Test<{ firstName: string; lastName: string }> onSubmit={onSubmit} schema={schema} >
方法3:调整FORM接口的类型约束(适配灵活场景)
如果需要接口兼容可选字段的schema,可以放宽schema的类型限制:
import { OptionalObjectSchema, SchemaOf } from 'yup'; interface FORM<P> { onSubmit: (d: P) => void; schema?: SchemaOf<P> | OptionalObjectSchema<Partial<P>>; }
这种方式适合多场景兼容需求,但优先推荐前两种方法保证类型严格性。
内容的提问来源于stack exchange,提问作者Asking

