Zod 和 Valibot 的异同

Zod 和 Valibot 的异同

两者的官网如下:

我这里准备了一些示例数据和获取数据的方法。接下来所有的操作都是基于这些数据来操作。

数据

mockdata/user.jsonjson
{
  "username": "月空人",
  "email": "whbbit@prop.show",
  "site": "https://www.prop.show",
  "org": "PropShow",
  "reading": [
    {
      "title": "Vue.js 设计与实现",
      "author": "霍春阳",
    },
    {
      "title": "Vue.js 设计与实现",
      "author": "霍春阳",
    },
  ],
}
mockdata/config.jsonjson
{
  "LOGIN_CONFIG": "{\"qqLogin\":2,\"wechatLogin\":true}",
}

获取数据的方法

api/user.tsts
import fs from 'node:fs/promises'

export const userData = await fs.readFile('./mockdata/user.json', 'utf-8')
    .then(val => JSON.parse(val))
api/config.tsts
import fs from 'node:fs/promises'

export const configData = await fs.readFile('./mockdata/config.json', 'utf-8')
    .then(val => JSON.parse(val))

基础的数据 Schema 的写法

validation/zod.tsts
import * as z from "zod";

import { userData } from "../api/user";

const UserSchema = z.object({
    username: z.string(),
    email: z.email(),
    site: z.url(),
    org: z.string(),
    reading: z.array(
        z.object({
            title: z.string(),
            author: z.string(),
        }),
    ),
});

对数据的的校验

基础校验

validation/zod.tsts
UserSchema.parse(userData)

safeParse

这样书写后如果报错会抛出一个错误阻碍后续代码操作,它们都提供了一个 safeParse 的写法

validation/zod.tsts
const result = UserSchema.safeParse(userData);
if (!result.success) {
    console.error(result.error);
}
else {
    console.log(result.data);
}

美化错误输出

这时的错误是不太容易阅读的,它们也都提供了美化错误输出的写法

validation/zod.tsts
const result = UserSchema.safeParse(userData);
if (!result.success) {
    console.error(z.flattenError(result.error));
}
else {
    console.log(result.data);
}

自定义数据校验

它们提供的数据校验都很全了,但是有时我们需要一个自定义的规则,比如我这里需要 username 必须是纯中文的字符,这时我们该如何操作呢?

validation/zod.tsts
const UserSchema = z.object({
    username: z.string().regex(/^[\u4E00-\u9FA5]+$/, { // [!code ++]
        error: "用户名必须是中文", // [!code ++]
    }), // [!code ++]
    email: z.email(),
    site: z.url(),
    org: z.string(),
    reading: z.array(
        z.object({
            title: z.string(),
            author: z.string(),
        }),
    ),
});

自动格式化数据

我们有时候需要对拿到的数据进行一些操作,我们可以在 Zod 和 Validate 中使用它们的 transform 来做。

下面的示例中,我们把 org 字符串转换为使用 - 连接。 PropShow -> prop-show

validation/zod.tsts
import { dash } from "radash";

const UserSchema = z.object({
    username: z.string().regex(/^[\u4E00-\u9FA5]+$/, {
        error: "用户名必须是中文",
    }),
    email: z.email(),
    site: z.url(),
    org: z.string().transform(val => dash(val)), // [!code ++]
    reading: z.array(
        z.object({
            title: z.string(),
            author: z.string(),
        }),
    ),
});

对 JSON 字符串进行转换和校验

我们还会遇到的一个情况就是从数据库中读出一个 JONS 格式的字符串,我们在使用的时候大部分时候都需要将其转换为标准的 JavaScript 对象。我们如何对这个 JSON 格式的字符串进行校验和自动转换为标准的 JavaScript 对象呢?

在上面我们准备的数据中,configData 就是这样一个数据。它代表我们可以使用的第三方登录平台。

我们要做的事就是校验它是否是正确的包含 qqLoginwechatLogin 的对象

validation/zod.tsts
const LoginConfigSchema = z.object({
    qqLogin: z.boolean(),
    wechatLogin: z.boolean(),
});

const LoginConfigStringSchema = z.object({
    LOGIN_CONFIG: z
        .string()
        .transform(val => JSON.parse(val))
        .pipe(LoginConfigSchema),
});

const result = LoginConfigStringSchema.safeParse(configData);

或者我们转过来,我们在调用接口的时候,有时候需要我们传递一个标准的 JSON 字符串,我们这时候也可以转过来,将 Object 自动转换为字符串

zod.tsts
const configData = {
    LOGIN_CONFIG: {
        qqLogin: true,
        wechatLogin: true
    }
}
const LoginConfigStringSchema = z.object({
    LOGIN_CONFIG: z.object({
        qqLogin: z.boolean(),
        wechatLogin: z.boolean(),
    }).transform(val => JSON.parse(val))
});
const result = v.safeParse(LoginConfigStringSchema, configData);
console.log(result.data)
// 输出结果
// {
//   LOGIN_CONFIG: "{\"qqLogin\":true,\"wechatLogin\":true}",
// }

中文错误的支持 —— i18n

在 Zod 中我们可以直接使用 z.config(z.locales.zhCN()) 来配置,在 Valibot 中使用 v.setGlobalConfig({ lang: 'zh-CN' }) 进行配置。

Valibot 你需要安装并引入 @valibot/i18n

JSON Schema

在 Zod 中你可以直接使用 z.toJSONSchema(LoginConfigStringSchema);在 Valibot 中你需要安装 @valibot/to-json-schema,使用方式为 v.safeParse(LoginConfigStringSchema, configData)

整体比较

比较项ZodValibot
写法链式操作函数组合
大小268.3k本体大小 80.4k@valibot/to-json-schema 大小为 8.4k, @valibot/i18n/zh-CN 大小为 8.2k

搭配视频观看

新故事即将发生
HTTP 状态码和短语