查看原文
其他

再见 Zod,你好 Valibot!

小懒 FED实验室 2024-02-12
关注下方公众号,获取更多热点资讯

今天是坚持日更的第142天,如果文章对您有帮助,点击关注、点赞、在看支持我


随着 TypeScript 在开发人员中的普及,对强大的验证库的需求变得越来越重要。验证库有助于确保数据的正确性、一致性和使用安全性。Zod、Joi、Yup、Valibot 是 TypeScript 最受欢迎的几个验证库。我们来看看这几个库的 NPM 包下载量:

从上图可以看出,Joi 出现最早,下载量最多;Zod 在 2023 年受到开发者追捧,迎来了指数级增长,超越 Yup;Valibot 发布 6 个月,Valibot 的周下载量已突破 50,000 次,Valibot 很有潜力成为 Zod/Yup 的替代品

什么是验证库?

在深入了解每个库的具体细节之前,我们先来定义一下验证库的含义。验证库是一种在代码中使用数据之前帮助确保数据有效的工具。在 TypeScript 中,这通常包括检查对象的形状和类型,以及验证输入参数和返回值。一个好的验证库应该易于使用、灵活且可扩展。

Zod 介绍

Zod 是一个相对较新的验证库,在 TypeScript 社区广受欢迎。它以简单的语法、强大的类型推断和性能而闻名。

Zod 旨在尽可能地方便开发人员使用。目标是消除重复的类型声明。使用 Zod,您只需声明一次验证器,Zod 就会自动推断出 TypeScript 的静态类型。将简单类型组合成复杂的数据结构也很容易。

亮点:

  • 零依赖。
  • 可在 Node.js 和所有现代浏览器中运行。
  • 语法简单:语法简单直观,易于使用,它使用可链式 API,读起来就像自然语言,让人很容易理解正在发生什么。
  • 稳健的类型推断:可以根据验证模式推断出复杂的类型,从而轻松处理复杂的数据结构。它还支持部分属性和可选属性,这在处理应用程序接口时特别有用。
  • 性能:在设计时充分考虑了性能。它重量轻、捆绑包小,压缩后仅有 8kb,并针对快速验证进行了优化。
  • 自定义错误信息:允许您自定义错误信息,从而更容易向用户提供有用的反馈.

Zod 的主要优点之一是简单。它易于上手,语法也易于理解。不过,它可能不是更复杂场景的最佳选择,因为它缺乏流行校验库(如 Joi、Yup等)的一些更高级功能。

Valibot 介绍

Valibot 受 Zod 启发,也使用模式轻松验证数据,但 API 更适合利用 tree-shaking,还能更好地压缩,相比 Zod 更小。无论是服务器上的传入数据,还是表单,甚至是配置文件。没有任何依赖性,可以在任何 JavaScript 环境中运行。

亮点:

  • 零依赖
  • 可在 Node.js 和所有现代浏览器中运行。
  • 语法简单:它不使用像 Zod 的链式 API 调用,而是采用更小的独立的函数的 API 设计。
  • 稳健的类型推断:通过静态类型推断实现完全类型安全,验证从字符串到复杂对象的所有内容。
  • 性能:采用模块化设计,可以更好的利用 tree-shaking,压缩后体积只有 300b,相比 Zod,体积更小。

Zod 代码示例:

import { string } from 'zod';
const emailValidator = string().email();

Zod 的这种 API 设计的一个问题是,在导入 string() 函数时,所有与字符串相关的验证器(IP 地址、UUID 等)都将包含在您的包中,无论我们是否使用这些功能。这会造成不必要的膨胀,并可能影响应用程序的性能,特别是当它在客户端使用时,客户端对包大小更加敏感。

Valibot 代码示例:

import { email, string } from 'valibot';
const emailValidator = string([email()]);

Valibot 的 string() 这里的函数仅包含检查输入数据是否为字符串的最低限度,而没有其他内容。附加功能是通过导入其他验证器来启用的,Valibot 将其称为“管道”。这确保了我们的捆绑包中只包含必要的逻辑,这也是 bundle 包体积更小的主要原因之一。

Zod 迁移 Valibot 快速指南

下面以一个同时用于客户端和服务器端的例子验证为例说明。

Zod 代码:

import { z } from 'zod';
 
const baseContactFormSchema = z.object({
  name: z.string().min(1'Name is required'),
  message: z.string().min(1'Message is required'),
});
 
export const contactFormSchema = z.discriminatedUnion('showInGuestbook', [
  baseContactFormSchema.extend({
    email: z
      .string()
      .min(1'Email is required')
      .email('Not a valid email'),
    subject: z.string().min(1'Subject is required'),
    showInGuestbook: z.literal(false),
  }),
  baseContactFormSchema.extend({
    email: z
      .string()
      .email('Not a valid email')
      .optional()
      .or(z.literal('')),
    subject: z.string().optional(),
    showInGuestbook: z.literal(true),
  }),
]);
 
export type ContactFormData = z.infer<typeof contactFormSchema>;

迁移后的 valibot 代码:

import {
  Output,
  email,
  literal,
  merge,
  minLength,
  object,
  optional,
  string,
  union,
  variant,
from 'valibot';
 
const baseContactFormSchema = object({
  name: string([minLength(1'Name is required')]),
  message: string([minLength(1'Message is required')]),
});
 
export const contactFormSchema = variant('showInGuestbook', [
  merge([
    baseContactFormSchema,
    object({
      email: string([
        minLength(1'Email is required'),
        email('Not a valid email'),
      ]),
      subject: string([minLength(1'Subject is required')]),
      showInGuestbook: literal(false),
    }),
  ]),
  merge([
    baseContactFormSchema,
    object({
      email: optional(
        union([string([email()]), literal('')], 'Not a valid email'),
      ),
      subject: optional(string()),
      showInGuestbook: literal(true),
    }),
  ]),
]);
 
export type ContactFormData = Output<typeof contactFormSchema>;

从上面迁移前后的代码看,最主要的区别就是 valibot 的模块化设计,每个模块都有单一职责。迁移前后的的 bundle size 对比:

- Zod: 12.37 KB Gzipped
+ Valibot: 1.72 KB Gzipped

体积缩小了近 90%!

显然,上面的用例代码并不是最复杂的,而且随着使用的验证器越来越多,差异的会逐渐放大。

结论

过去的6个月,Valibot 增长很快。Valibot 很有潜力成为 Zod/Yup 的替代品,但文档质量是其最大的障碍。很多开发者开始尝试使用 Valibot,同时享受较小的捆绑包。如果你有新的内部项目,建议你试试看。但对于更大、更严肃的项目来说,采用 Valibot 可能还为时过早,因为文档的缺乏是一个不容忽视的风险。

展望未来,个人建议作者和贡献者能够花一些精力在文档建设上。现在的功能和 API 已经支持的不错了,足以和现有的产品竞争。文档完善之后,可以更好地让开发者懂得如何使用它们。

大家都在看

继续滑动看下一个

再见 Zod,你好 Valibot!

小懒 FED实验室
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存