前端数据校验太难?一个 Zod 就够了

一、Zod 是什么?

Zod 是一个TypeScript 优先的类型校验库,核心作用是:

  1. 用简洁的语法定义「数据校验规则 + TypeScript 类型」(一份代码,双重收益);
  2. 校验前端表单、API 响应、环境变量等任意数据,返回清晰的错误信息;
  3. 零依赖、体积小,适配前端 / Node.js 项目,是替代 Joi、Yup 的主流选择。

二、5 分钟快速上手(Vue3/Vite 项目为例)

步骤 1:安装

bash

运行

bash 复制代码
npm install zod
# 或 yarn/pnpm
pnpm add zod

步骤 2:核心用法(定义 → 校验 → 提取类型)

Zod 的核心逻辑是:先定义 Schema 校验规则 → 用 Schema 校验数据 → 自动推导 TS 类型。

typescript

运行

js 复制代码
// src/utils/validate.ts
import { z } from 'zod';

// 1. 定义校验规则(Schema)
const UserSchema = z.object({
  // 必选字符串,非空
  username: z.string().min(2, '用户名至少2个字符').max(20),
  // 可选数字,大于0
  age: z.number().optional().positive('年龄必须为正数'),
  // 邮箱格式校验
  email: z.string().email('请输入正确的邮箱格式'),
  // 枚举值限制
  role: z.enum(['admin', 'user', 'guest'], '角色只能是admin/user/guest'),
  // 嵌套对象
  address: z.object({
    city: z.string(),
    street: z.string().optional()
  })
});

// 2. 提取 TS 类型(无需手动写 interface)
type User = z.infer<typeof UserSchema>;

// 3. 校验数据
function validateUser(data: unknown) {
  try {
    // 严格校验:不符合规则会抛错
    const validData = UserSchema.parse(data);
    console.log('校验通过', validData);
    return { success: true, data: validData };
  } catch (error) {
    // 捕获错误并格式化
    if (error instanceof z.ZodError) {
      const errMsg = error.errors.map(item => ({
        field: item.path.join('.'), // 错误字段(如 address.city)
        message: item.message       // 错误提示
      }));
      return { success: false, errors: errMsg };
    }
    return { success: false, errors: [{ field: 'unknown', message: '未知错误' }] };
  }
}

// 测试:校验合法数据
const validUser = {
  username: '张三',
  email: 'zhangsan@test.com',
  role: 'user',
  address: { city: '北京' }
};
console.log(validateUser(validUser)); // success: true

// 测试:校验非法数据
const invalidUser = {
  username: '张', // 长度不足
  email: '123',   // 邮箱格式错误
  role: 'super',  // 枚举值错误
  address: { city: 123 } // 类型错误
};
console.log(validateUser(invalidUser)); 
// success: false,errors 包含所有错误字段和提示

步骤 3:项目实战场景

场景 1:校验前端表单(Vue3 示例)

vue

html 复制代码
<!-- src/components/LoginForm.vue -->
<template>
  <form @submit.prevent="submitForm">
    <input v-model="form.email" placeholder="邮箱" />
    <div v-if="errors.email">{{ errors.email }}</div>
    
    <input v-model="form.password" placeholder="密码" />
    <div v-if="errors.password">{{ errors.password }}</div>
    
    <button type="submit">提交</button>
  </form>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { z } from 'zod';

// 定义表单校验规则
const LoginSchema = z.object({
  email: z.string().email('请输入正确的邮箱'),
  password: z.string().min(6, '密码至少6位')
});
type LoginForm = z.infer<typeof LoginSchema>;

// 表单数据
const form = ref<LoginForm>({ email: '', password: '' });
const errors = ref<Record<string, string>>({});

// 提交表单
const submitForm = () => {
  // 清空之前的错误
  errors.value = {};
  
  // 校验数据(safeParse 不抛错,返回结果)
  const result = LoginSchema.safeParse(form.value);
  if (!result.success) {
    // 格式化错误信息
    result.error.errors.forEach(item => {
      errors.value[item.path[0]] = item.message;
    });
    return;
  }
  
  // 校验通过,调用接口
  console.log('表单数据合法', result.data);
};
</script>
场景 2:校验 API 响应

typescript

运行

ts 复制代码
// src/api/user.ts
import { z } from 'zod';
import axios from 'axios';

// 定义 API 响应规则
const UserListSchema = z.array(
  z.object({
    id: z.number(),
    name: z.string(),
    avatar: z.string().url().optional() // 可选URL
  })
);

// 请求接口并校验响应
async function getUserList() {
  const res = await axios.get('/api/users');
  // 校验响应数据,确保符合预期
  const validData = UserListSchema.parse(res.data);
  return validData;
}
场景 3:校验环境变量(Vite 项目)

typescript

运行

ts 复制代码
// src/utils/env.ts
import { z } from 'zod';

// 定义环境变量规则
const EnvSchema = z.object({
  VITE_API_BASE: z.string().url('API地址必须是合法URL'),
  VITE_GA_ID: z.string().optional()
});

// 校验 Vite 环境变量
const env = EnvSchema.parse(import.meta.env);
// 导出类型安全的环境变量
export default env;

三、高频实用 API 速查

表格

API 示例 作用
z.string().min(2) 字符串,最小长度 2
z.number().int() 整数
z.boolean() 布尔值
z.array(z.string()) 字符串数组
z.object({ a: z.string() }) 对象校验
z.enum(['a', 'b']) 枚举值限制
z.date() 日期类型
z.any() 任意类型
z.optional(z.string()) 可选字符串
z.nullable(z.string()) 可空字符串
schema.parse(data) 严格校验,失败抛错
schema.safeParse(data) 安全校验,返回结果(不抛错)
z.infer<typeof schema> 从 Schema 提取 TS 类型

总结

  1. Zod 核心是「Schema 定义 → 数据校验 → 自动推导 TS 类型」,一份代码兼顾校验和类型;
  2. 常用场景:表单校验、API 响应校验、环境变量校验,适配前端 / Node.js;
  3. 核心 API:z.object/z.string/z.number 定义规则,parse/safeParse 校验数据,z.infer 提取类型。

上手关键:先定义 Schema,再用 safeParse 校验数据(避免抛错),最后格式化错误信息返回给用户。

相关推荐
jay神4 分钟前
基于 YOLOv8 的森林火灾检测系统(Web 版)
前端·yolo
code2cat8 分钟前
HTML基础篇之第一张网页:从index.html到浏览器里的任务清单
前端·html
miss1 小时前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan2 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真2 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment2 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan2 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么2 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
上海懒图科技2 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue
西安小哥3 小时前
端侧跑大模型,真正的门槛不在参数量:一次 596 秒到 10 秒的压缩路径复盘
前端·人工智能