Vee-Validate 4结合Yup嵌套对象设置initialValues后类型错误问题
问题场景
使用组合式API结合Vee-Validate 4定义嵌套表单校验规则时,添加初始值后触发TypeScript类型错误:
Element implicitly has an 'any' type because expression of type "currency.name" can't be used to index
type 'Partial<Record<"currency", string | undefined>>'.
Property 'currency.name' does not exist on type 'Partial<Record<"currency", string | undefined>>'.
核心问题:TypeScript错误推断errors类型为仅包含currency字段的平面结构,而非嵌套结构;同时currency字段被误推断为string类型,而非定义的SelectOption类型。
相关代码:
类型定义
export type SelectOption = { name: string label?: string }
表单逻辑(出错版本)
import { useForm, useField } from 'vee-validate' import { object, string } from 'yup' const { handleSubmit, errors } = useForm({ validationSchema: object({ currency: object().shape({ name: string().notOneOf(['any'], errorMessages.required), }), }), initialValues: { currency: { name: 'any', label: 'Choose currency', }, } }) const { value: currency } = useField<SelectOption>('currency')
模板代码
<base-select v-model="currency" :options="currencies" :error="errors['currency.name']" />
可行解决方案
方案1:显式声明表单值泛型类型
给useForm传入明确的表单结构泛型,让TypeScript正确推断errors的嵌套类型:
// 先定义完整的表单值类型 type FormValues = { currency: SelectOption } const { handleSubmit, errors } = useForm<FormValues>({ validationSchema: object({ currency: object().shape({ name: string().notOneOf(['any'], errorMessages.required), }), }), initialValues: { currency: { name: 'any', label: 'Choose currency', }, } })
此时errors会被正确推断为支持嵌套访问的类型,errors['currency.name']或errors.currency?.name均能通过类型校验。
方案2:直接用路径语法获取嵌套字段错误
通过useField直接指定嵌套字段路径,自动获取该字段的错误信息,无需手动处理errors对象:
// 获取currency.name字段的错误 const { error: currencyNameError } = useField('currency.name') // 保留currency字段的绑定 const { value: currency } = useField<SelectOption>('currency')
模板中直接使用获取到的错误变量:
<base-select v-model="currency" :options="currencies" :error="currencyNameError" />
方案3:优化Yup Schema的类型匹配
确保Yup Schema与TypeScript类型严格对齐,避免推断偏差:
type FormValues = { currency: SelectOption } // 定义独立的currency Schema并标记为必填 const currencySchema = object({ name: string().notOneOf(['any'], errorMessages.required), }).defined() // 强制该对象为必填,避免推断为可选类型 const { handleSubmit, errors } = useForm<FormValues>({ validationSchema: object({ currency: currencySchema, }), initialValues: { currency: { name: 'any', label: 'Choose currency', }, } })
内容的提问来源于stack exchange,提问作者Ришат Ризванов

