模式验证库——zod

引言💭

在学习react过程中接触了一下zod,这篇文章来深入了解一下什么是zod。


一、Zod 是什么?

Zod 是一个 TypeScript 优先的模式验证库,用于在运行时验证和解析数据结构,确保数据类型安全。

这是官网中给的例子:

typescript 复制代码
import { z } from "zod/v4";

// 定义 Schema(模式)
// 这里定义了一个名为 User 的 Schema,它表示一个对象,
// 其中必须包含一个 name 属性,且 name 必须是字符串类型(z.string())。
const User = z.object({
  name: z.string(),
});
 
// 待验证的数据
// input 是一个未知的、可能不受信任的数据(比如来自 API 响应、用户输入等),
// 需要验证是否符合 User Schema。
const input = { /* stuff */ };
 
// 解析和验证数据
// User.parse(input) 会检查 input 是否符合 User Schema:
// 如果符合,返回解析后的数据(类型安全,TypeScript 会推断 data 的类型为 { name: string })。
// 如果不符合,Zod 会抛出一个错误(ZodError)。
const data = User.parse(input);
 
// 由于 data 已经通过 Zod 验证,可以放心使用 data.name,因为它一定是 string 类型。
console.log(data.name);

Zod 的核心思想是:

定义模式(schema) → 推导类型 → 验证数据

特征

  • 零外部依赖
  • 适用于 Node.js 和所有现代浏览器
  • 微小:2kb 核心包(gzip 压缩)
  • 不可变 API:方法返回一个新实例
  • 简洁的界面
  • 适用于 TypeScript 和纯 JS
  • 内置 JSON Schema 转换
  • 广泛的生态系统

基本用法

建议查阅官方文档,这里不作过多赘述。


看到这里是不是有种熟悉的感觉,这不是老朋友interface吗?

二、Zod Schema和Interface

Zod Schema 和 TypeScript 的 interface确实在结构上很相似,它们都用来定义对象的"形状"和"属性"。但它们的用途、时机和能力有明显区别:


🧩 1. 编译时 vs 运行时

比较项 interface Zod Schema
类型检查时机 编译时(开发时) 运行时
作用 提供类型提示、静态检查 对传入数据进行实际的运行时校验
能否在运行时使用 会被擦除 运行时可判断是否合法

🔍 2. 示例对比

interface 示例(仅开发时检查

typescript 复制代码
interface User {
  name: string;
  age: number;
}

function greet(user: User) {
  console.log(`Hello, ${user.name}`);
}

// 编译时能检查,但运行时不会验证结构

Zod 示例(运行时校验)

javascript 复制代码
import { z } from "zod";

const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
});

function greet(user: unknown) {
  const parsed = UserSchema.parse(user); // 若不合法会抛错
  console.log(`Hello, ${parsed.name}`);
}

🧠 3. 用途对比

用途 interface Zod
类型提示 ❌(需通过 .infer 获取类型)
运行时输入验证(API、表单)
提供 IDE 自动补全 ❌(Zod Schema 可反推出类型)
数据转换(默认值、类型转换) ✅(Zod 提供 .transform()

🔁 4. 配合使用

最佳实践Zod + TypeScript 联用

ini 复制代码
const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
});

type User = z.infer<typeof UserSchema>; // 自动提取类型

这样既能进行运行时校验 ,又能享受类型推导带来的开发体验。


总结一句话

interface 是开发阶段的类型说明,Zod 是运行阶段的数据验证器。它们可以配合使用,各司其职。

三、在 React 项目中的使用

1. 验证表单数据

Zod 可以用来验证用户在表单中输入的数据,搭配 react-hook-form 特别方便。

示例:表单验证

tsx 复制代码
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {z} from "zod";

// 定义 Zod 验证 schema(运行时验证规则)
const schema = z.object({
  name: z.string().min(2, "名字至少2个字符"),
  age: z.number().min(18, "必须年满18岁"),
});

// 使用 z.infer 推导出 schema 对应的 TypeScript 类型
type FormData = z.infer<typeof schema>;

export default function MyForm() {
  // 初始化表单,使用 useForm
  const {
    register, // 注册表单字段,连接 input 元素和 React Hook Form
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>({
    resolver: zodResolver(schema), // 指定使用 zodResolver(schema),让 Zod 参与验证
  });

  // 提交处理函数,只有通过验证时才会调用
  const onSubmit = (data: FormData) => {
    console.log(data);
  };

  return (
  // handleSubmit(onSubmit)会拦截提交事件:
  // 验证失败 → 不提交;验证成功 → 调用 onSubmit
    <form onSubmit={handleSubmit(onSubmit)}>
    
      <input {...register("name")} placeholder="名字" />
      <!--- 如果errors.name存在则显示message:"名字至少2个字符",不存在则不显示-->
      {errors.name && <p>{errors.name.message}</p>}

      <input type="number" {...register("age", { valueAsNumber: true })} placeholder="年龄" />
      <!--如果errors.age存在则显示message:"必须年满18岁",不存在则不显示-->
      {errors.age && <p>{errors.age.message}</p>}

      <button type="submit">提交</button>
      
    </form>
  );
}

2. 校验 API 返回的数据

例如,fetch 后对返回结果进行类型和结构的校验:

tsx 复制代码
const userSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
});

fetch("/api/user")
  .then(res => res.json())
  .then(data => {
    // 使用 Zod 的 safeParse 进行安全校验
    // 返回的是一个包含 success 和 data/error 的对象
    const result = userSchema.safeParse(data);
    if (result.success) {
      // 校验成功,result.data 是类型安全的对象
      console.log(result.data);
    } else {
      // 校验失败,result.error 是详细的验证错误信息
      console.error("数据结构不符合预期", result.error);
    }
  });

3. 组件 props 验证(开发阶段)

虽然 TypeScript 已经能检查 props 类型,但你可以使用 Zod 在运行时对 props 进行额外校验(比如防止外部调用者传错结构)。

tsx 复制代码
import React from "react";
import {z} from "zod";

// 定义 props 的 schema
const userCardPropsSchema = z.object({
  name: z.string(),
  age: z.number().int().min(0),
});

type UserCardProps = z.infer<typeof userCardPropsSchema>;

// 定义函数组件,并使用推导出来的 props 类型
export const UserCard: React.FC<UserCardProps> = (props) => {
  // 使用 Zod 的 safeParse 方法在运行时校验 props 的合法性
  const result = userCardPropsSchema.safeParse(props);

  if (!result.success) {
    // 校验失败,打印错误信息,避免渲染非法数据
    console.error("UserCard props 验证失败:", result.error);
    return <div>传入的 props 不合法</div>;
  }

  // 解构通过验证的数据,类型安全
  const { name, age } = result.data;

  // 正常渲染组件内容
  return (
    <div>
      <h2>{name}</h2>
      <p>年龄: {age}</p>
    </div>
  );
};

四、Zod 的优势(特别适用于 React)

优点 描述
类型推导 使用 z.infer 可以自动获得类型定义
TypeScript 友好 完美支持 TS,无需重复定义类型
表单库兼容性 react-hook-form 等库配合默契
可组合性强 支持嵌套 schema、交叉验证、联合类型等
运行时验证 提供真实的运行时类型检查(TS 在编译时)

五、与其他库的比较(Yup, Joi)

特性 Zod Yup Joi
TypeScript 支持 ✅ 极好 ⚠️ 一般 ❌ 较差
学习曲线 简单 稍复杂 较复杂
表单支持 ✅ react-hook-form 优先支持
Schema 推导 ✅ 自动推导 ❌ 需手动 ❌ 需手动

结语✒️

知识点+1✨✨✨

相关推荐
ai产品老杨5 分钟前
减少交通拥堵、提高效率、改善交通安全的智慧交通开源了。
前端·vue.js·算法·ecmascript·音视频
lexiangqicheng10 分钟前
JS-- for...in和for...of
开发语言·前端·javascript
粥里有勺糖30 分钟前
视野修炼-技术周刊第122期 | 发光图片制作
前端·javascript·github
Carlos_sam1 小时前
OpenLayers:封装Tooltip
前端·javascript
工呈士1 小时前
MobX与响应式编程实践
前端·react.js·面试
嘉小华1 小时前
Android Lifecycle 使用
前端
Sherry0071 小时前
实时数据传输协议:WebSocket vs MQTT
前端·websocket
然我1 小时前
JavaScript的OOP独特之道:从原型继承到class语法
前端·javascript·html
腹黑天蝎座1 小时前
如何更好的实现业务中图片批量上传需求
前端
嘉小华1 小时前
Android Lifecycle 源码解析
前端