什么是 Zod
Zod:github
是一个 TypeScript 优先的数据格式声明和验证库。用过其特有的语法来声明数据的类型。
使用 Zod 只需要声明一次,就可以由 Zod 自动推断出 TS 的类型,并且拥有该类型的动态验证方法。
与 TS 静态校验数据格式不同,Zod 可以动态对数据进行校验,比如在前后端交互中,对于接口获取数据的校验或者在前端对表单进行校验就需要 Zod 这一类数据动态校验的工具库。
在 Zod 中,一般用 schema
来表示 Zod 所定义的数据类型。
安装
npm install zod
deno add npm:zod # deno
yarn add zod # yarn
bun add zod # bun
pnpm add zod # pnpm
使用
声明基本类型
为方便 TS 开发者学习 Zod,这里列一下 TS 和 Zod 的类型对应表
基础数据
import { z } from 'zod'
// string
z.string()
// number
z.number()
// bigint
z.bigint()
// boolean
z.boolean()
// Date
z.date()
// symbol
z.symbol()
// undefiend
z.undefined()
// null
z.null()
// void
z.void()
// any
z.any()
// unknown
z.unknown()
// never
z.never()
promise
使用z.promise
来定义 Promise 类型
const numberPromise = z.promise(z.number());
对象
在 zod 中定义对象类型,可以使用z.object
来定义:
比如某个对象的类型是
interface User {
id: string;
name: string;
password: string;
createTime: number;
}
其对应的 zod 结构为:
import { z } from "zod"
const userSchema = z.object({
id: z.string(),
name: z.string(),
password: z.string(),
createTime: z.number()
})
数组
可以用z.array
来定义数组
比如一个数组的 TS 类型是
type Users = string[]
使用 Zod 定义则为
import { z } from "zod"
const usersSchema = z.array(z.string())
Map & Set
使用 z.map 和 z.set 来定义 Map 和 Set 类型
const stringNumberMap = z.map(z.string(), z.number());
type StringNumberMap = z.infer<typeof stringNumberMap>;
// type StringNumber = Map<string, number>
const numberSet = z.set(z.number());
type NumberSet = z.infer<typeof numberSet>;
// Set<number>
枚举
方法 1:使用z.enum
定义
const FruitEnumSchema = z.enum(['Apple', 'Orange'])
这里要注意必须直接传入,如果不直接传入,Zod 就无法自动推断出枚举的类型
除非使用 as const
帮助 Zod 推断枚举的类型
const FRUIT = ['Apple', 'Orange'] as const
const FruitEnumSchema = z.enum(FRUIT)
想要使用的话,则可以通过 .enum
来访问枚举
FruitEnumSchema.enum.Apple
或者使用 .options
来检索选项,得到一个元组
FruitEnumSchema.options // ['Apple', 'Orange']
方法二:使用 z.nativeEnum
来使用现有的枚举类型直接生成 Schema
enum Fruits {
Apple,
Banana,
}
const FruitEnumSchema = z.nativeEnum(Fruits);
自定义类
可以使用z.instanceof
来检查输入是否是一个类的实例,可以用于验证从第三方库中导出的类。
class Test {
name: string;
}
const TestSchema = z.instanceof(Test);
函数
使用z.function
来定义函数类型,通过链式调用args
和returns
来定义函数的参数和返回值
const myFunction = z
.function()
.args(z.string(), z.number())
.returns(z.boolean());
可选
可以用z.optional()
使任何 Schema 变为可选
const schema = z.optional(z.string());
或者用.optional()
方法使一个现有的 Schema 成为可选的
const schema = z.string().optional();
nullable
与转换为可选类似,可以使用nullable
将 Schema 变为可以是 null
const nullableString = z.nullable(z.string());
也可以直接调用.nullable()
方法使一个现有的 Schema 成为 null 的类型
const nullableString = z.string().nullable()
nullish
相当于是optional
和nullable
的组合
联合
可以使用z.union
将两个 Schema 联合起来,相当于 ts 中的 |
;也可以直接用.or()
方法,将一个已存在的 Schema 与另一个联合起来
const stringOrNumber = z.union([z.string(), z.number()]);
const stringOrNumber = z.string().or(z.number());
合并
可以使用z.intersection
来合并两个 Schema,或者用.and
方法
const Person = z.object({
name: z.string(),
});
const Employee = z.object({
role: z.string(),
});
const EmployedPerson = z.intersection(Person, Employee);
// equivalent to:
const EmployedPerson = Person.and(Employee);
针对于对象,Zod 更推荐用.merge
来合并
Record
在ts中我们常用 Record<string, any>
来定义类似 { [k: string]: any }
的类型,在 Zod 中可以使用z.record
来定义 Schema
const userSchema = z.object({ name: z.string() });
const userStoreSchema = z.record(userSchema);
常用方法
parse
任何 Zod Schema 都可以使用parse
方法来检查传入的数据是否符合 Schema 的定义。如果不符合,则会抛出错误
const stringSchema = z.string();
stringSchema.parse("fish"); // => returns "fish"
stringSchema.parse(12); // throws Error('Non-string type: number');
safeParse
用法作用同 parse 方法,但是在不符合数据定义的情况下不会抛出错误
stringSchema.safeParse(12);
// => { success: false; error: ZodError }
stringSchema.safeParse("billie");
// => { success: true; data: 'billie' }
refine
除了基本的数据格式,还可以通过 refine
来自定义数据校验的规则。
const myString = z.string().refine((val) => val.length <= 255, {
message: "String can't be more than 255 characters",
})
也可以在 refine 中设置异步的校验规则,但这样的话,必须使用.parseAsync
方法来解析数据,否则 Zod 会抛出一个错误
const stringSchema = z.string().refine(async (val) => val.length > 20);
const value = await stringSchema.parseAsync("hello"); // => hello
除了自定义规则,
z.number
、z.string
、z.array
等都提供了很多自带的验证功能,比如数字的大小,数组的大小限制等等
获取TS类型
可以使用z.infer<typeof mySchema>
来获取 Schema 所定义的 TS 类型。
const A = z.string();
type A = z.infer<typeof A>; // string