注册
web

前端进阶必须会的Zod !

大家好,我是白露。


今天我想和大家分享一个我最近在使用的TypeScript库 —— Zod。简单来说,Zod是一个用于数据验证的库,它可以让你的TypeScript代码更加安全和可靠。


最近几个月我一直在使用Zod,发现它不仅解决了我长期以来的一些痛点,还大大提高了我的开发效率。我相信,这个库也能帮助到许多和我有同样困扰的TypeScript开发者们。


1. 为什么需要Zod?


作为一个热爱TypeScript的程序员,我一直在寻找能够增强类型安全性的方法。


最近几年,我主要使用TypeScript进行开发。原因很简单:TypeScript提供了优秀的静态类型检查,特别是对于大型项目来说,它的类型系统可以帮助我们避免许多潜在的运行时错误。


然而,尽管TypeScript的类型系统非常强大,但它仍然存在一些局限性。特别是在处理运行时数据时,TypeScript的静态类型检查无法完全保证数据的正确性。这就是我开始寻找额外的数据验证解决方案的原因。


在这个过程中,我尝试了多种数据验证库,如Joi、Yup等。但它们要么缺乏与TypeScript的良好集成,要么使用起来过于复杂。直到我发现了Zod,它完美地解决了我的需求。


2. Zod是什么?


Zod是一个TypeScript优先的模式声明和验证库。它允许你创建复杂的类型安全验证模式,并在运行时执行这些验证。Zod的设计理念是"以TypeScript类型为先",这意味着你定义的每个Zod模式不仅可以在运行时进行验证,还可以被TypeScript编译器用来推断类型。


使用Zod的主要优势包括:



  1. 类型安全: Zod提供了从运行时验证到静态类型推断的端到端类型安全。
  2. 零依赖: Zod没有任何依赖项,这意味着它不会给你的项目增加额外的包袱。
  3. 灵活性: Zod支持复杂的嵌套对象和数组模式,可以处理几乎任何数据结构。
  4. 可扩展性: 你可以轻松地创建自定义验证器和转换器。
  5. 性能: Zod经过优化,可以处理大型和复杂的数据结构,而不会影响性能。

3. 如何使用Zod?


让我们通过一些实际的例子来看看如何使用Zod。


3.1 基本类型验证


import { z } from 'zod';

// 定义一个简单的字符串模式
const stringSchema = z.string();

// 验证
console.log(stringSchema.parse("hello")); // 输出: "hello"
console.log(stringSchema.parse(123)); // 抛出 ZodError

3.2 对象验证


const userSchema = z.object({
  name: z.string(),
  age: z.number().min(0).max(120),
  email: z.string().email(),
});

type User = z.infer<typeof userSchema>; // 自动推断类型

const user = {
  name: "Alice",
  age: 30,
  email: "alice@example.com",
};

console.log(userSchema.parse(user)); // 验证通过

3.3 数组验证


const numberArraySchema = z.array(z.number());

console.log(numberArraySchema.parse([123])); // 验证通过
console.log(numberArraySchema.parse([1"2"3])); // 抛出 ZodError

4. Zod的高级用法


Zod不仅可以处理基本的类型验证,还可以处理更复杂的场景。


4.1 条件验证


const personSchema = z.object({
  name: z.string(),
  age: z.number(),
  drivingLicense: z.union([z.string(), z.null()]).nullable(),
}).refine(data => {
  if (data.age < 18 && data.drivingLicense !== null) {
    return false;
  }
  return true;
}, {
  message: "未成年人不能持有驾-照",
});

4.2 递归模式


const categorySchema: z.ZodType<Category> = z.lazy(() => z.object({
  name: z.string(),
  subcategories: z.array(categorySchema).optional(),
}));

type Category = z.infer<typeof categorySchema>;

4.3 自定义验证器


const passwordSchema = z.string().refine(password => {
  // 至少8个字符,包含大小写字母和数字
  const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
  return regex.test(password);
}, {
  message"密码必须至少8个字符,包含大小写字母和数字",
});

5. Zod与前端框架的集成


Zod可以很好地与各种前端框架集成。


这里我们以React为例,看看如何在React应用中使用Zod进行表单验证。


import { z } from 'zod';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

const schema = z.object({
  username: z.string().min(3).max(20),
  email: z.string().email(),
  password: z.string().min(8),
});

type FormData = z.infer<typeof schema>;

function SignupForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolverzodResolver(schema),
  });

  const onSubmit = (data: FormData) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("username")} placeholder="Username" />
      {errors.username && <span>{errors.username.message}</span>}
      
      <input {...register("email")} placeholder="Email" />
      {errors.email && <span>{errors.email.message}</span>}
      
      <input {...register("password")} type="password" placeholder="Password" />
      {errors.password && <span>{errors.password.message}</span>}
      
      <button type="submit">Sign Up</button>

    </form>


  );
}

6. Zod与数据库的结合


Zod不仅可以用于前端验证,还可以与后端数据库模式定义完美结合。以下是一个使用Prisma和Zod的例子:


import { z } from 'zod';
import { Prisma } from '@prisma/client';

const userSchema = z.object({
  id: z.number().optional(),
  name: z.string().min(3),
  email: z.string().email(),
  age: z.number().min(18),
  createdAt: z.date().optional(),
  updatedAt: z.date().optional(),
});

type User = z.infer<typeof userSchema>;

// 使用Zod模式来定义Prisma模型
const userModel: Prisma.UserCreateInput = userSchema.omit({ id: true, createdAt: true, updatedAt: true }).parse({
  name: "John Doe",
  email: "john@example.com",
  age: 30,
});

// 现在可以安全地将这个对象传递给Prisma的create方法
// prisma.user.create({ data: userModel });

7. Zod的性能优化


虽然Zod非常强大,但在处理大型数据结构时,可能会遇到性能问题。以下是一些优化建议:



  1. 延迟验证: 对于大型对象,考虑使用z.lazy()来延迟验证。
  2. 部分验证: 使用z.pick()z.omit()来只验证需要的字段。
  3. 缓存模式: 如果你频繁使用相同的模式,考虑缓存它们。
  4. 异步验证: 对于复杂的验证逻辑,考虑使用异步验证器。

8. Zod vs 其他验证库


Zod并不是市场上唯一的验证库。让我们简单比较一下Zod与其他流行的验证库:



  1. Joi: Joi是一个功能强大的验证库,但它不是TypeScript优先的,这意味着你需要额外的工作来获得类型推断。
  2. Yup: Yup与Zod非常相似,但Zod的API设计更加直观,而且性能通常更好。
  3. Ajv: Ajv是一个高性能的JSON Schema验证器,但它的API相对复杂,学习曲线较陡。
  4. class-validator: 这是一个基于装饰器的验证库,非常适合与TypeORM等ORM一起使用,但它需要使用实验性的装饰器特性。

相比之下,Zod提供了一个平衡的解决方案:它是TypeScript优先的,性能优秀,API直观,并且不需要任何实验性特性。


总而言之,通过使用Zod,你可以:



  1. 减少运行时错误
  2. 提高代码的可读性和可维护性
  3. 自动生成TypeScript类型
  4. 简化前后端之间的数据验证逻辑

开始使用Zod吧,让你的TypeScript代码更安全、更强大!


写了这么多,大家不点赞或者star一下,说不过去了吧?


延伸阅读



作者:青玉白露
来源:juejin.cn/post/7426923218952847412

0 个评论

要回复文章请先登录注册