Yup从0.32.11迁移至1.0.2时的TypeScript类型错误问题
问题背景
现有React状态变量:
const [selectedFormtype, setSelectedFormtype] = useState<Nullable<MyFormTypeVm>>()
相关类型定义:
type Nullable<T> = T | null interface MyFormTypeVm { readonly id: NonNullable<string> readonly labelCompanyId: Nullable<string> } interface MyFormVm { companyId: Nullable<string> // 其他属性省略 }
在yup@0.32.11版本中,原本可用的验证方案:
const validationSchema: yup.SchemaOf<MyFormVm> = yup.object().shape({ companyId: yup.string().when([], { is: () => selectedFormtype?.labelCompanyId, then: yup.string() .required('Company-id is required') .matches(/^[8|9]\d{8}$/i, 'Company-id has to start with 8 or 9') }) ).required()
按照yup迁移指南改写验证逻辑后,出现TS2322类型错误,改写后的代码:
const validationSchema: yup.ObjectSchema<MyFormVm> = yup.object().shape({ companyId: yup.string().when('other', ([], schema) => { return selectedFormtype?.labelCompanyId ? schema .required('required text goes here') .matches(/^[8|9]\d{8}$/i, 'regex text goes here') : schema }) })
已在tsconfig.json中配置:
"strictNullChecks": true, "strictFunctionTypes": false
错误原因分析
when参数错误:验证逻辑依赖外部状态selectedFormtype,而非表单内的other字段,传入'other'会导致TS类型推导混乱。- 类型不兼容:
MyFormVm的companyId是Nullable<string>,但触发必填规则后,schema会强制要求非空字符串,和原接口类型冲突。 - 缺少nullable声明:原schema未显式标记
companyId允许为null,导致TS无法识别动态的可空/必填约束。
解决方法
1. 修正when的触发参数
因为依赖外部状态,when的第一个参数应传空数组[],而非表单字段名:
yup.string().when([], ([], schema) => { ... })
2. 显式处理可空类型
给yup.string()添加.nullable(),让TS识别companyId的可空特性,同时兼容动态必填规则:
const validationSchema: yup.SchemaOf<MyFormVm> = yup.object().shape({ companyId: yup.string().nullable().when([], ([], schema) => { return selectedFormtype?.labelCompanyId ? schema .required('required text goes here') .matches(/^[8|9]\d{8}$/i, 'regex text goes here') : schema }) }).required()
3. 确保验证逻辑响应状态变化
由于selectedFormtype是React状态,需用useMemo依赖该状态生成schema,避免状态更新后验证逻辑不生效:
const validationSchema = useMemo(() => yup.object().shape({ companyId: yup.string().nullable().when([], ([], schema) => { return selectedFormtype?.labelCompanyId ? schema .required('required text goes here') .matches(/^[8|9]\d{8}$/i, 'regex text goes here') : schema }) }).required(), [selectedFormtype])
4. 类型断言兜底(谨慎使用)
如果上述方法仍有类型错误,可通过类型断言强制TS认可schema兼容性:
const validationSchema: yup.ObjectSchema<MyFormVm> = yup.object().shape({ companyId: (yup.string().when([], ([], schema) => { return selectedFormtype?.labelCompanyId ? schema .required('required text goes here') .matches(/^[8|9]\d{8}$/i, 'regex text goes here') : schema }) as yup.Schema<Nullable<string>>) }).required()
内容的提问来源于stack exchange,提问作者Roar S.
相关产品推荐
相关产品推荐

