Zod 基础用法

Zod 基础用法

现在我们越来越多的在 UI 组件库里找到 Zod 的存在,Zod 是什么?我们为什么要用 Zod 呢?

根据其官网说法,zod 利用静态类型推断进行 TypeScript 优先模式验证。在 shadcn、nuxt ui 等组件库中,其主要是用来进行表单的校验;在一些 js 全栈项目里,它用来规定项目的数据结构。

我们就来简单的看一下它是怎么使用的。

这里我使用 pnpm 作为包管理工具,并使用 vue 项目举例。

安装

shell
pnpm add zod

一些常用的内容

一些常用的字符串的验证

创建字符串模式时,你可以自定义一些常见的错误信息

ts
const name = z.string({
    required_error: "Name is required",
    invalid_type_error: "Name must be a string",
});

自定义错误消息

使用验证方法时,你可以传递一个附加参数,以提供自定义错误信息

ts
z.string().min(5, { message: "Must be 5 or more characters long" });
z.string().max(5, { message: "Must be 5 or fewer characters long" });
z.string().length(5, { message: "Must be exactly 5 characters long" });
z.string().email({ message: "Invalid email address" });
z.string().url({ message: "Invalid url" });
z.string().emoji({ message: "Contains non-emoji characters" });
z.string().uuid({ message: "Invalid UUID" });
z.string().includes("tuna", { message: "Must include tuna" });
z.string().startsWith("https://", { message: "Must provide secure URL" });
z.string().endsWith(".com", { message: "Only .com domains allowed" });
z.string().datetime({ message: "Invalid datetime string! Must be UTC." });
z.string().ip({ message: "Invalid IP address" });

特定的数字验证

ts
z.number().gt(5); // 最小为 5
z.number().gte(5); // alias .min(5)
z.number().lt(5); // 最大为 5
z.number().lte(5); // alias .max(5)

z.number().int(); // 必须是一个整数

z.number().positive(); //     > 0
z.number().nonnegative(); //  >= 0
z.number().negative(); //     < 0
z.number().nonpositive(); //  <= 0

z.number().multipleOf(5); // Evenly divisible by 5. Alias .step(5)

z.number().finite(); // value must be finite, not Infinity or -Infinity
z.number().safe(); // value must be between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGE

和字符串一样,也可以传递第二个参数来自定义错误消息

对象类型

ts
const userSchema = z.object({
    username: z.string(),
    password: z.string()
        .min(5, { message: '密码最小为 5 位' })
        .max(10, { message: '密码最大为 10 位' }),
})

// 可以使用 z.infer来提取 schema 的 ts 类型
type User = z.infer<typeof userSchema>
// 相当于 type User = {username: string, password: string}

受 TypeScript 内置的Pick和Omit工具类型的启发,所有 Zod 对象模式都有.pick和 .omit方法,可以返回一个修改后的版本

要想只保留某些 Key,使用 .pick .

ts
const passwordSchema = userSchema.pick({ password: true });
type Password = z.infer<typeof passwordSchema>; // => type Password = {password: string}

要删除某些 Key,请使用 .omit .

ts
const passwordSchema = userSchema.pick({ username: true });
type Password = z.infer<typeof passwordSchema>; // => type Password = {password: string}

optional

你可以用z.optional()使任何模式成为可选:

ts
const userSchema = z.object({
    username: z.string(),
    password: z.string(),
    age: z.number().optional()
})

可以使用 coerce 对原始类型进行强制转换

ts
// 对传入的 id 做校验并强制转换为数字类型
// /detail/:id
const paramsSchema = z.object({
    id: z.coerce.number()
})
const { id } = paramsSchema.parse(router)

还有很多其他的校验内容,可以去 zod 的官网或 github 仓库去查看

使用技巧

1. 在 vue 项目中校验 router 传递的参数

这里使用safeParse进行校验,校验失败后不会抛出错误,我们可以根据它返回的 success 是否为 true 来判断校验是否通过。并可以在 error 中得到校验失败的信息进行相应的处理。

detail.vuevue
<script lang="ts" setup>
import { useRoute } from "vue-router"
import { z } from "zod"
const route = useRoute()

const paramsSchema = z.object({
    id: z.coerce.number({ message: "id必须是一个数字" }),
})
const { success, data: params, error } = paramsSchema.safeParse(route.params)
</script>

<template>
    <div>detail {{ params?.id }}</div>
    <pre v-if="!success">{{ error }}</pre>
</template>

同理,我们也可以校验它的 query 类型,此处便不再重复。

2. 传递数据时只传递指定的字段并对其进行校验

向接口传递数据时,我们有时会有一些多余的参数,此时我们可以构建一个 schema 来对传递的参数做校验,校验后获得的值为 schema 中规定的数据结构,可以帮助我们校验数据类型并且去除 schema 中未定义的多余参数

同理,如果我们是一个 node 的接口,我们也可以使用这个技巧来向前端传递指定 schema 类型的数据。

新故事即将发生
翻译:如何使用 Vitest 在 Vue 中进行视觉回归测试?

评论区

评论加载中...