Skip to content

校验结果 ​

validate、parse 等函数返回什么:结果由哪些部分组成、数据会发生什么变化、错误的结构如何。以下所有示例都是 tinyval 的真实输出。

结果由什么组成 ​

validate 和 validateAsync 返回一个包含四个字段的对象:

字段数据有效时存在错误时
validtruefalse
data清洗后的数据undefined
errors{}每个字段的第一个错误:{ 'items.0.qty': '...' }
issues[]全部错误的详细信息:代码、路径、参数、文本

parse 和 parseAsync 直接返回 data,或抛出 ValidationError。

数据有效 —— data 中有什么 ​

data 不是输入数据,而是经过 Schema 处理后的结果。示例:

ts
const Order = object({
  name: pipe(string(), trim(), minLength(2)),
  email: pipe(string(), trim(), toLowerCase(), email()),
  age: optional(pipe(coerce.number(), min(18))),
  comment: optional(string()),
  middleName: optional(nullable(string())),
  newsletter: optional(coerce.boolean(), false),
  items: array(object({ title: string(), qty: pipe(coerce.number(), min(1)) })),
});

validate(Order, {
  name: '  Ivan ',
  email: ' IVAN@Mail.RU ',
  age: '30',
  comment: '',
  middleName: null,
  items: [{ title: 'Book', qty: '2' }],
  isAdmin: true,
});
json
{
  "valid": true,
  "data": {
    "name": "Ivan",
    "email": "ivan@mail.ru",
    "age": 30,
    "middleName": null,
    "newsletter": false,
    "items": [{ "title": "Book", "qty": 2 }]
  },
  "errors": {},
  "issues": []
}
字段输入data 中原因
name' Ivan ''Ivan'trim
email' IVAN@Mail.RU ''ivan@mail.ru'trim + toLowerCase
age'30'30coerce.number —— 字符串变成了数字
comment''无此字段optional 中的空字符串表示“未提供”,字段不会出现在 data 中
middleNamenullnullnullable 保留 null
newsletter缺失false来自 optional(…, false) 的默认值
items[0].qty'2'2数组中的 coerce.number
isAdmintrue无此字段多余字段被删除(object 的 strip 模式)

因此 data 可以直接存入数据库:类型已转换,没有多余字段,TypeScript 类型由 Schema 推导。

存在错误 —— errors 和 issues ​

ts
validate(Order, { name: 'I', email: 'bad', age: '15', items: [{ title: 'Book', qty: '0' }, { qty: '1' }] });
js
{
  "valid": false,
  "data": undefined,
  "errors": {
    "name": "Must be at least 2 characters long",
    "email": "Invalid email",
    "age": "Must be at least 18",
    "items.0.qty": "Must be at least 1",
    "items.1.title": "Required"
  },
  "issues": [
    { "code": "minLength", "path": ["name"], "params": { "min": 2 }, "message": "Must be at least 2 characters long" },
    { "code": "email", "path": ["email"], "params": {}, "message": "Invalid email" },
    { "code": "min", "path": ["age"], "params": { "min": 18 }, "message": "Must be at least 18" },
    { "code": "min", "path": ["items", 0, "qty"], "params": { "min": 1 }, "message": "Must be at least 1" },
    { "code": "required", "path": ["items", 1, "title"], "params": {}, "message": "Required" }
  ]
}

errors ​

“路径 → 第一个错误文本”的对象。便于在字段旁显示错误:errors.email、errors['items.0.qty']。

  • 路径用点连接,数组索引为数字:items.1.title。
  • 值本身的错误(Schema 不是对象时)在键 '' 下:validate(string(), 42).errors → { '': 'Must be a string' }。
  • 每个字段一个错误 —— 按 pipe 中规则顺序的第一个。

issues ​

按 Schema 字段顺序排列的全部错误数组。每个错误包含:

字段示例用途
code'minLength'错误代码 —— 用于自定义逻辑和翻译。全部代码见 错误信息
path['items', 0, 'qty']数组形式的路径:索引为数字,便于嵌套表单
params{ min: 1 }规则参数 —— 用于在客户端生成自定义文本
message'Must be at least 1'已生成的文本,已应用语言、label 和自定义信息

字段的全部错误与 Laravel 格式 ​

默认每个字段一个错误。使用 { all: true } 选项时,issues 包含全部错误,flatten 会按字段分组:

ts
const r = validate(object({ password: pipe(string(), minLength(8), email()) }), { password: 'abc' }, { all: true });

r.errors;           // { password: 'Must be at least 8 characters long' }
flatten(r.issues);  // { password: ['Must be at least 8 characters long', 'Invalid email'] }

parse 与 ValidationError ​

出错时 parse 会抛出 ValidationError —— 其中包含相同的 errors 和 issues,message 合并为一行,便于记录日志:

ts
try {
  parse(Order, { name: 'I' });
} catch (e) {
  e instanceof ValidationError; // true
  e.message; // 'name: Must be at least 2 characters long; email: Required; items: Required'
  e.errors;  // { name: 'Must be at least 2 characters long', email: 'Required', items: 'Required' }
  e.issues;  // [{ code, path, params, message }, …]
}

Standard Schema ​

通过 schema['~standard'].validate 得到的是标准格式的结果 —— { value } 或仅包含 message 和 path 的 { issues }:

json
{
  "issues": [
    { "message": "Must be at least 2 characters long", "path": ["name"] },
    { "message": "Required", "path": ["email"] },
    { "message": "Required", "path": ["items"] }
  ]
}

TypeScript 中的结果类型 ​

Result<T> 是联合类型:检查 valid 之后,TypeScript 就知道 data 是否存在。详见 TypeScript。

ts
const r = validate(Order, input);
if (r.valid) r.data.items[0].qty; // number
else r.errors;                    // Record<string, string>

另请参阅 ​