2026/4/22 21:14:36
网站建设
项目流程
月嫂网站建设,自助建站实验报告,交换友情链接的意义是什么,php网站文件夹结构我见过许多因为运行时数据不匹配而导致的崩溃#xff0c;也曾写过无数防御性代码和 any 断言#xff0c;哈哈 #x1f604;。TypeScript 的类型安全本来就不该止步于编译期。直到遇见 Zod#xff0c;Zod 不仅是一个验证库#xff0c;它为 TypeScript 带来运行时安全#…我见过许多因为运行时数据不匹配而导致的崩溃也曾写过无数防御性代码和any断言哈哈 。TypeScript 的类型安全本来就不该止步于编译期。直到遇见 ZodZod 不仅是一个验证库它为 TypeScript 带来运行时安全是目前最优雅、最彻底的解决方案。我们为何需要 ZodTypeScript 最让人上瘾的地方在于编译时类型检查但这也是它的最大谎言因为类型在运行时彻底消失你需要小心小心再小心使用 TypeScript 并不代表类型安全。/* by 01130.hk - online tools website : 01130.hk/zh/px2rem.html */ interface User { name: string; age: number; role: admin | user; } fetch(/api/user).then(res res.json()).then((data: User) { // 编译通过但如果 data.role 返回的是 administrator运行会报错 console.log(data.role.toUpperCase()); });而 Zod 的答案是只定义一次 Schema既得到运行时验证又得到完美的 TypeScript 类型。/* by 01130.hk - online tools website : 01130.hk/zh/px2rem.html */ const UserSchema z.object({ name: z.string(), age: z.number(), role: z.enum([admin, user]), }); type User z.infertypeof UserSchema;通过 Schema 推断出完美类型 User无需二次声明。这样 UserSchema 用于运行时验证User 用于类型推断。Zod 入门npm install zodimport { z } from zod; // 基础类型 const StringSchema z.string(); const NumberSchema z.number().int().positive();核心 APIparse 和 safeParse我建议优先使用.safeParse()。const schema z.string(); try { const result schema.parse(123); console.log(result); } catch (error) { console.error(验证失败:, error.errors); }parse 抛出 ZodError, 你需要通过try catch捕获错误否则导致程序崩溃。const schema z.string(); const result schema.safeParse(123); if (result.success) { console.log(验证成功:, result.data); } else { console.log(验证失败:, result.error.errors); }safeParse 返回{ success: true, data: T }或{ success: false, error: ZodError }你可以通过 success 判断是否验证成功然后通过 data 获取验证后的数据或者通过error.errors获取错误信息, 这样你可以优雅地处理错误。构建复杂数据模型const AddressSchema z.object({ street: z.string(), city: z.string(), zipCode: z.string().regex(/^\d{5}$/), }); const UserSchema z.object({ id: z.string().uuid(), name: z.string().min(2).max(50), email: z.string().email(), age: z.number().int().min(13).max(120), address: AddressSchema.optional(), // 可选嵌套对象 tags: z.array(z.string()).default([]), // 默认值 role: z.enum([admin, user, moderator]), status: z.enum([active, inactive]).default(active), });组合技巧这些是我最常用的.extend()是 Zod 最被低估的特性之一。它让你能以面向对象的方式构建 Schema 体系比 interface 继承更安全因为运行时验证也会继承。// 扩展 const AdminSchema UserSchema.extend({ permissions: z.array(z.string()), });比较常见的是实现查询接口的分页查询 Schema分页查询 Schema 包含 page 和 pageSize 字段自其他 Schema 可以继承分页查询 Schema 并添加其他字段。const PageSchema z.object({ page: z.number().min(1).default(1), pageSize: z.number().min(1).max(100).default(10), }); const UserPageSchema PageSchema.extend({ name: z.string().min(2).max(50), }); type UserPage z.infertypeof UserPageSchema;合并, 优先级后者覆盖前者。const MergedSchema UserSchema.merge(z.object({ role: z.literal(admin), // 强制覆盖 }));交集。const IntersectionSchema z.intersection(UserSchema, z.object({ isVerified: z.boolean(), }));进阶模式与精细校验可辨识联合Discriminated Union比如我们用它来处理 Redux Action。可辨识联合Discriminated Union也称为标签联合Tagged Union或代数数据类型Algebraic Data Type是一种高级类型系统特性用于表示可能是多种不同类型之一的值。const ActionSchema z.discriminatedUnion(type, [ z.object({ type: z.literal(INCREMENT), payload: z.number() }), z.object({ type: z.literal(DECREMENT), payload: z.number() }), z.object({ type: z.literal(SET_USER), payload: UserSchema }), ]); type Action z.infertypeof ActionSchema;z.discriminatedUnion比手动写.or()更清晰TypeScript 窄化narrowing也更完美。字符串高级校验z.string() .min(8, 至少8位) .regex(/[A-Z]/, 必须含大写字母) .regex(/[a-z]/, 必须含小写字母) .regex(/[0-9]/, 必须含数字) .regex(/[^A-Za-z0-9]/, 必须含特殊字符);通过 Transform 验证后自动转换这太棒了比如写 restful 接口时我们希望 Query id 是 number 类型但是传入 string 类型我们可以借助 Transform 自动转换为 number 类型。const IdSchema z.string().transform(str parseInt(str));推断 TypeScript 类型修改 Schema类型自动更新无需手动更新类型完美同步。type User z.infertypeof UserSchema;与 TypeScript 原生 enum 互操作。enum Role { Admin admin, User user, } const RoleSchema z.nativeEnum(Role);常见应用场景API 响应验证async function apiFetchT extends z.ZodType( url: string, schema: T ): Promisez.inferT { const res await fetch(url); const data await res.json(); const result schema.safeParse(data); if (!result.success) { throw new Error(API验证失败: ${result.error.message}); } return result.data; } // 使用 const user await apiFetch(/api/user, UserSchema);表单验证与 React-Hook-Form 完美结合类型安全 错误信息自动同步。AI 非常喜欢这套方案AI 生成的代码非常不容易出错。const formSchema z.object({ email: z.string().email(邮箱格式错误), password: z.string().min(8, 密码至少8位), confirm: z.string(), }).refine(data data.password data.confirm, { message: 两次密码不一致, path: [confirm], }); type FormData z.infertypeof formSchema; const { register, handleSubmit, formState: { errors } } useFormFormData({ resolver: zodResolver(formSchema), });但是我们最常用的 antd 的 Form 组件与 Zod 结合并不完美 #40580。表单一旦复杂字段之间的关联性就更多了如果都在 jsx 中处理代码的可读性、可维护性就大大降低如果把字段的定义以及验证单独提取出来形成业务实体对应的实体逻辑无疑更好。社区有人为此实现了一个 antd-zod 库是目前我比较推荐的方案。import { createSchemaFieldRule } from antd-zod; const CustomFormValidationSchema z.object({ fieldString: z.string(), fieldNumber: z.number(), }); const rule createSchemaFieldRule(CustomFormValidationSchema); export function SimpleForm() { return ( Form Form.Item labelString field namefieldString rules{[rule]} Input/ /Form.Item Form.Item labelNumber field namefieldNumber rules{[rule]} InputNumber/ /Form.Item Button htmlTypesubmitSubmit/Button /Form ); };环境变量验证const envSchema z.object({ DATABASE_URL: z.string().url(), NODE_ENV: z.enum([development, production, test]), JWT_SECRET: z.string().min(32), }); type Env z.infertypeof envSchema; export const env envSchema.parse(process.env);对于环境变量校验我推荐你使用 t3-env,使用无效的环境变量部署应用程序是一件麻烦事。这个包可以帮助你避免这种情况。它支持使用任何 Standard Schema 兼容验证器当然包括 Zod。定义环境变量// src/env.mjs import { createEnv } from t3-oss/env-nextjs; // or core package import { z } from zod; export const env createEnv({ /* * Serverside Environment variables, not available on the client. * Will throw if you access these variables on the client. */ server: { DATABASE_URL: z.string().url(), OPEN_AI_API_KEY: z.string().min(1), }, /* * Environment variables available on the client (and server). * * Youll get type errors if these are not prefixed with NEXT_PUBLIC_. */ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, /* * Due to how Next.js bundles environment variables on Edge and Client, * we need to manually destructure them to make sure all are included in bundle. * * Youll get type errors if not all variables from server client are included here. */ runtimeEnv: { DATABASE_URL: process.env.DATABASE_URL, OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, }, });使用时具有自动完成和类型推断功能import { env } from ../env.mjs; export const GET (req: Request) { const DATABASE_URL env.DATABASE_URL; // use it... };服务端应用tRPC 示例tRPC 是一个端到端类型安全的服务端框架。tRPC 的核心魔力就在于 Zod。输入验证、类型推断、自动生成客户端类型全程零配置。服务端实现文章发布接口使用 Zod 验证输入前端类型推断端到端类型安全对于 AI 自动补全和提升生成代码质量也是非常有帮助的AI 生成结构化数据许多语言模型都能够生成结构化数据通常定义为使用“JSON modes”或“tools”。然而您需要手动提供模式然后验证生成的数据因为 LLM 可能会产生错误或不完整的结构化数据。Vercel AI SDK 通过在generateText上使用output属性标准化了模型提供商之间的结构化对象生成。 和streamText。您可以使用 Zod schemasValibot 或 JSON schemas 来指定您想要的数据结构AI 模型将生成符合该结构的数据。使用generateText和Output.object()从提示中生成结构化数据。该模式还用于验证生成的数据确保类型安全和正确性。import { generateText, Output } from ai; import { deepseek } from ai-sdk/deepseek; import { z } from zod; const { output } await generateText({ model: deepseek(deepseek-v3.1), output: Output.object({ schema: z.object({ recipe: z.object({ name: z.string(), ingredients: z.array( z.object({ name: z.string(), amount: z.string() }), ), steps: z.array(z.string()), }), }), }), prompt: 生成一份扬州炒饭食谱, });与其他验证库对比库TypeScript 支持类型推断体积学习成本生态推荐场景Zod原生一流完美~6KB低极强所有 TS 项目强烈推荐Yup需 cast差~20KB中强老项目、JS 项目Joi差无大中强Node.js 后端io-ts好FP 风格好中高弱喜欢函数式编程的团队AJV差无小快中强纯 JSON 验证场景总结这才是 TypeScript 应该有的样子。