yup 动态验证 - 初探

4,066 阅读3分钟

Yup

官方解释:

Yup is a JavaScript schema builder for value parsing and validation. Define a schema, transform a value to match, validate the shape of an existing value, or both. Yup schema are extremely expressive and allow modeling complex, interdependent validations, or value transformations.

大致译为:

Yup 是一个用于值解析和验证的 JavaScript 架构构建器。 定义模式、转换值以匹配、验证现有值的形状,或两者兼而有之。 Yup 模式具有极强的表现力,允许对复杂的、相互依赖的验证或值转换进行建模。

Schema

schema 是对数据的一种描述。例:yup.string() 描述数据是字符串类型。我们可以 requiredminmax修饰方法对其进行修饰,也可以使用 test 方法来订制更复杂的描述。

除了 stringyup 还内置了 numberbooleandataarrayobject 模式,它们都继承mixed 模式。通过 mixed 我们可以对 schema 进行订制 。

依据使用的方式将 schema 大致划分为以下两大类 schema typesschema types

type schema

type schema 主要包含有 mixedstringnumberbooleandatearrayobject 等。

yup.mixed()

mixed.cast()

mixed.cast(value: any, options = {}): any

尝试将传入的值强制转换为与模式匹配的值,转换失败的话可能返回 nullNaN 或其他字符信息。

示例:

// 数字类型 1 将会转化为字符串 '1'
yup.string().min(2).required().cast(1)

mixed.when()

mixed.when(keys: string | Array<string>, builder: object | (value, schema)=> Schema): Schema

通过同级或同级子字段作为判定条件来对其他字段匹配 schema

示例:

// 方式一:is~then/otherwise 形式
let schema = object({
  isBig: boolean(),
  count: number()
    .when('isBig', {
      // is: (val) => val == true,
      is: true,
      then: yup.number().min(5), // isBig 为 true 时 count 使用该 schema
      otherwise: yup.number().min(0), // isBig 不为 true 时 count 使用该 schema
    })
  	// $other 可以替换 options 参数内 context 对象中的值
    .when('$other', (other, schema) => (other === 4 ? schema.max(6) : schema)), //  schema.max(6) 生效
});

// 方式二:回调函数形式
let schema = yup.object({
  isBig: yup.boolean(),
  count: yup.number().when('isBig', (isBig, schema) => {
    return isBig ? schema.min(5) : schema.min(0);
  }),
});

await schema.validate({ isBig: true, count: 4 }, { context: { other: 4 } });

mixed.test()

mixed.test(name: string, message: string | function, testFun: function): Schema

向验证链添加测试函数。在投射任何对象后运行测试定制特定逻辑的验证提示信息。

testFun function
  • 普通函数 function (val) {}
  • 箭头函数 (val, context) => {}

说明:测试函数为普通函数上下文对象为 函数内 this;为箭头函数上下文对象为函数第二个参数 context

context type
type ContextType = {
  path: string // 当前验证的路径字符串
  schema: object // 测试运行所针对的解析模式对象
  options: object // 调用 validate() 或 isValid() 的选项对象
  parent: object // 嵌套模式下父对象的值
  originalValue: any // 验证的源数据信息
  createError: { path: string; message: string; params: object } // 创建并返回验证错误
} 

示例:

// 提示信息中的 path 变量见上面 ContextType 对象属性说明 
// 同步校验
let jerrySchema = yup.string().require('名称不能为空').test(
  'isJerry',
  '${path}名称不正确,不是 Jerry', // 默认错误提示信息【回调函数返回 false 时使用】
  (val, context) => {
    if (val !== 'Jerry') {
      // 提示 createError 创建的错误信息【将覆盖默认错误信息提示】
      retrun context.createError({
        message: '名称不正确,不是 Jerry',
      })
    }
    return true;
  }
)

// 异步校验
let asyncJerrySchema = yup.string().require('名称不能为空').test(
  'isJerry',
  '${path}名称不正确,不是 Jerry', // 默认错误提示信息
  async (val, context) => {
    const res = await fetch('/isJerry/' + val);
    // true 存在校验通过,false 时不存在显示默认错误提示信息
    return res.data;
  }
)

await jerrySchema.isValid('Jerry'); // => true
await asyncJerrySchema.isValid('Tom'); // => false

yup.array()

array.of()

array.of(type: Schema): Schema

指定数组元素的架构。 of() 是可选的,当省略时,数组模式将不会验证其内容。

示例:

let schema = yup.array().of(
	// yup.object({...}) 与 yup.object().shape({...}) 在这等同,详情见下文 yub.object().shape()
  yup.object().shape({
    name: yup
    	.string().trim()
    	.max(50, '不能超过 50 字符')
    	.required('姓名不能为空')
    	.test(
        'name',
        '名称不正确,不是 Jerry',
        (val) => val === 'Jerry'
      ),
    age: yup.number().min(0, '年龄不能小于 0').required('年龄不能为空')
	})
)

await schema.validate([{ name: 'Arvinjun', age: 18 }]);

yup.object()

object.shape()

object.shape(fields: object, noSortEdges?: Array<[string, string]>): Schema

定义对象的键和所述键的模式。 请注意,您可以链接形状方法,其作用类似于对象扩展。

示例:

object({
  a: string(),
  b: number(),
}).shape({
  b: string(),
  c: number(),
});

// 等同于

object({
  a: string(),
  b: string(),
  c: number(),
});

method schema

method schema 主要包含有 reachaddMethodreflazyValidtionError 等。

lazy()

yup.lazy((value: any) => Schema): Lazy

创建在验证/转换时评估的架构。对于为多态字段和数组创建递归模式(如树)很有用。

注意 ⚠️:在定义父子递归对象模式时,您需要将子对象的 default() 重置为 undefined, 否则当您强制转换对象时,对象将会无限嵌套!

示例:

let node = object({
  id: number(),
  child: yup.lazy(() => node.default(undefined)),
});

let renderable = yup.lazy((val) => {
  switch (typeof val) {
    case 'number':
      return number();
    case 'string':
      return string();
    default:
      return mixed();
  }
});

let renderables = array().of(renderable);

References

yup official document