前端数据校验太难?一个 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 校验数据(避免抛错),最后格式化错误信息返回给用户。

相关推荐
陈林梓2 小时前
Axios 二次封装指南 & 跨系统复用建议
前端
ZoeLandia2 小时前
基于 qiankun 的应用间页面跳转
前端·前端框架
前端 贾公子2 小时前
unplugin-icons == elementPlus自动引入icon
前端·javascript·vue.js
YFLICKERH2 小时前
【Python-Web后端开发框架】Flask | Django | FastAPI | Tornado 选型与 使用 | 特性
前端·python·flask
光影少年2 小时前
说说模块化规范?CommonJS和ES Module的区别?
前端·javascript·elasticsearch
telllong2 小时前
C++20 Modules:从入门到真香
java·前端·c++20
叫我一声阿雷吧2 小时前
JS 入门通关手册(21):原型链:JS 继承的底层原理
开发语言·javascript·前端面试·原型链·js继承·js进阶·js面向对象
是Yu欸3 小时前
LangGraph 智能体状态管理与决策
java·javascript·数据库