Zod:现代的 TypeScript 数据验证库

2025-02-10 08:30:09

在开发现代化的Web应用时,数据验证是一个不可或缺的环节。无论是从前端接收用户输入,还是从后端处理数据,都需要确保数据的正确性和一致性。为了简化这一过程,许多开发者转向了各种数据验证库。今天我们要介绍的是一个专门为TypeScript设计的高效且易用的数据验证库——Zod

Zod Logo

什么是 Zod?

Zod 是一个用于TypeScript的数据验证和解析库。它提供了一种声明式的方式来定义数据模式(Schemas),并通过这些模式对数据进行验证。Zod 的核心优势在于其类型安全、简洁的API以及丰富的验证功能。Zod 的设计目标是为开发者提供一种简单、强大且类型友好的方式来处理数据验证,使其成为构建可靠Web应用的理想选择。

功能特性

类型安全

Zod 最大的特点之一是其与TypeScript类型的无缝集成。通过使用Zod,你可以定义强类型的Schema,并在编译时得到类型检查的支持。这不仅减少了运行时错误的可能性,还提供了更好的开发体验。

  • 定义Schema:

    import { z } from 'zod';
    
    const userSchema = z.object({
      id: z.number(),
      name: z.string(),
      email: z.string().email()
    });
    
    type User = z.infer<typeof userSchema>;
    
  • 类型推断: 使用 z.infer 可以自动推断出Schema对应的类型,无需手动定义接口或类型别名。

简洁的API

Zod 的API设计非常直观和简洁,使得开发者可以轻松上手并快速编写复杂的验证逻辑。无论是简单的字段验证,还是复杂的嵌套对象和数组验证,Zod 都能提供清晰的解决方案。

  • 基本验证:

    const schema = z.object({
      username: z.string().min(3).max(20),
      password: z.string().min(8)
    });
    
    const result = schema.safeParse({ username: 'john', password: 'password123' });
    if (result.success) {
      console.log('Validation successful:', result.data);
    } else {
      console.error('Validation failed:', result.error.issues);
    }
    
  • 嵌套对象验证:

    const addressSchema = z.object({
      street: z.string(),
      city: z.string(),
      zipCode: z.string()
    });
    
    const userSchema = z.object({
      id: z.number(),
      name: z.string(),
      address: addressSchema
    });
    
    const data = {
      id: 1,
      name: 'John Doe',
      address: {
        street: '123 Main St',
        city: 'Anytown',
        zipCode: '12345'
      }
    };
    
    const parsedData = userSchema.safeParse(data);
    if (parsedData.success) {
      console.log('Parsed data:', parseddata.data);
    } else {
      console.error('Validation failed:', parsedData.error.issues);
    }
    
  • 数组验证:

    const productSchema = z.object({
      id: z.number(),
      name: z.string(),
      price: z.number().positive()
    });
    
    const productsSchema = z.array(productSchema);
    
    const products = [
      { id: 1, name: 'Laptop', price: 999 },
      { id: 2, name: 'Mouse', price: -20 }
    ];
    
    const validatedProducts = productsSchema.safeParse(products);
    if (validatedProducts.success) {
      console.log('Validated products:', validatedProducts.data);
    } else {
      console.error('Validation failed:', validatedProducts.error.issues);
    }
    

丰富的验证功能

Zod 提供了丰富的验证功能,包括但不限于:

  • 基本类型验证:字符串、数字、布尔值等。

  • 复杂类型验证:对象、数组、联合类型等。

  • 自定义验证:允许开发者定义自己的验证逻辑。

  • 转换器:可以在验证过程中对数据进行转换。

  • 默认值:可以为字段设置默认值。

  • 非空检查:确保字段不是空值或空字符串。

  • 条件验证:根据某些条件动态应用不同的验证规则。

  • 自定义验证:

    const isAdult = (value: number) => value >= 18;
    
    const personSchema = z.object({
      name: z.string(),
      age: z.number().refine(isAdult, { message: 'You must be an adult to proceed.' })
    });
    
    const personData = {
      name: 'Alice',
      age: 17
    };
    
    const parsedPerson = personSchema.safeParse(personData);
    if (parsedPerson.success) {
      console.log('Parsed person:', parsedPerson.data);
    } else {
      console.error('Validation failed:', parsedPerson.error.issues);
    }
    
  • 转换器:

    const userSchema = z.object({
      fullName: z.string().transform(name => name.trim())
    });
    
    const userData = { fullName: '  John Doe  ' };
    const parsedUser = userSchema.safeParse(userData);
    if (parsedUser.success) {
      console.log('Parsed user:', parsedUser.data); // { fullName: 'John Doe' }
    } else {
      console.error('Validation failed:', parsedUser.error.issues);
    }
    
  • 默认值:

    const userSchema = z.object({
      id: z.number(),
      name: z.string().default('Guest')
    });
    
    const userData = { id: 1 };
    const parsedUser = userSchema.parse(userData);
    console.log(parsedUser); // { id: 1, name: 'Guest' }
    
  • 非空检查:

    const userSchema = z.object({
      id: z.number(),
      name: z.string().nonempty()
    });
    
    const userData = { id: 1, name: '' };
    const parsedUser = userSchema.safeParse(userData);
    if (parsedUser.success) {
      console.log('Parsed user:', parsedUser.data);
    } else {
      console.error('Validation failed:', parsedUser.error.issues); // Validation failed: [ { code: 'invalid_type', expected: 'nonempty', received: 'empty_string', path: ['name'], message: 'Expected a non-empty string, received an empty string' } ]
    }
    
  • 条件验证:

    const userSchema = z.object({
      isAdmin: z.boolean(),
      permissions: z.union([
        z.literal('user').when('isAdmin', { is: false, then: z.literal('user') }),
        z.literal('admin').when('isAdmin', { is: true, then: z.literal('admin') })
      ])
    });
    
    const adminData = { isAdmin: true, permissions: 'admin' };
    const parsedAdmin = userSchema.safeParse(adminData);
    if (parsedAdmin.success) {
      console.log('Parsed admin:', parsedAdmin.data); // { isAdmin: true, permissions: 'admin' }
    } else {
      console.error('Validation failed:', parsedAdmin.error.issues);
    }
    
    const userData = { isAdmin: false, permissions: 'admin' };
    const parsedUser = userSchema.safeParse(userData);
    if (parsedUser.success) {
      console.log('Parsed user:', parsedUser.data);
    } else {
      console.error('Validation failed:', parsedUser.error.issues); // Validation failed: [ { code: 'invalid_union', unionErrors: [ { issues: [Object], _tag: 'Left' }, { issues: [], _tag: 'Right' } ], path: ['permissions'], message: 'Invalid input' } ]
    }
    

易于集成

Zod 的设计旨在易于集成到现有的TypeScript项目中。无论你是在前端还是后端开发,Zod 都可以轻松地与你的应用集成。以下是一些常见的集成示例:

  • React 集成:

    import React, { useState } from 'react';
    import { z } from 'zod';
    
    const formSchema = z.object({
      username: z.string().min(3).max(20),
      password: z.string().min(8)
    });
    
    const LoginForm: React.FC = () => {
      const [username, setUsername] = useState('');
      const [password, setPassword] = useState('');
      const [errors, setErrors] = useState<z.ZodFormattedError>([]);
    
      const handleSubmit = (event: React.FormEvent) => {
        event.preventDefault();
    
        const result = formSchema.safeParse({ username, password });
        if (result.success) {
          console.log('Form submitted:', result.data);
        } else {
          setErrors(result.error.format());
        }
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <div>
            <label htmlFor="username">Username</label>
            <input
              type="text"
              id="username"
              value={username}
              onChange={(e) => setUsername(e.target.value)}
            />
            {errors.username && <p>{errors.username._errors.join(', ')}</p>}
          </div>
          <div>
            <label htmlFor="password">Password</label>
            <input
              type="password"
              id="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
            />
            {errors.password && <p>{errors.password._errors.join(', ')}</p>}
          </div>
          <button type="submit">Submit</button>
        </form>
      );
    };
    
    export default LoginForm;
    
  • Express.js 集成:

    import express, { Request, Response } from 'express';
    import { z } from 'zod';
    
    const app = express();
    app.use(express.json());
    
    const userSchema = z.object({
      id: z.number(),
      name: z.string(),
      email: z.string().email()
    });
    
    app.post('/users', (req: Request, res: Response) => {
      const result = userSchema.safeParse(req.body);
      if (result.success) {
        const validatedUser = result.data;
        console.log('Validated user:', validatedUser);
        res.status(200).send(validatedUser);
      } else {
        res.status(400).json(result.error.issues);
      }
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    

总结

Zod 是一个功能强大且易用的TypeScript数据验证库。它的类型安全、简洁的API以及丰富的验证功能使其成为现代Web开发中的理想选择。无论你是处理表单验证、

colinhacks
zod 是一个TypeScript数据类型验证库。从简单的 String类型到复杂的嵌套对象。
TypeScript
MIT
37.6 k