Zod 快速入门和实践

TS

🌙 Zod 快速入门和实践

Zod 是一个 TypeScript-first 的 schema 声明和校验库,它允许你以类型安全的方式定义和校验数据结构。以下是快速入门指南和一些最佳实践,帮助你在项目中高效使用 Zod。

🌙 1. 安装 Zod

首先,你需要安装 Zod:

npm install zod
1

🌙 2. 基本使用

定义和校验简单的数据结构:

import { z } from 'zod';

// 定义一个简单的 schema
const userSchema = z.object({
  name: z.string(),
  age: z.number().positive(),
});

// 校验数据
const user = userSchema.parse({ name: 'Alice', age: 25 });
console.log(user); // { name: 'Alice', age: 25 }
1
2
3
4
5
6
7
8
9
10
11

🌙 3. 错误处理

如果数据不符合 schema,Zod 会抛出一个错误:

try {
  userSchema.parse({ name: 'Alice', age: -5 });
} catch (error) {
  console.error(error.errors); // 输出详细的错误信息
}
1
2
3
4
5

🌙 4. 可选字段和默认值

处理可选字段并设置默认值:

const userSchema = z.object({
  name: z.string(),
  age: z.number().positive().optional().default(18),
});

const user = userSchema.parse({ name: 'Alice' });
console.log(user); // { name: 'Alice', age: 18 }
1
2
3
4
5
6
7

🌙 5. 复杂 schema

支持嵌套对象、数组等复杂结构:

const addressSchema = z.object({
  street: z.string(),
  city: z.string(),
});

const userSchema = z.object({
  name: z.string(),
  age: z.number().positive(),
  address: addressSchema,
});

const user = userSchema.parse({
  name: 'Alice',
  age: 25,
  address: {
    street: '123 Main St',
    city: 'Springfield',
  },
});
console.log(user);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

🌙 6. 最佳实践

  • 类型推断:Zod 可以自动推断 TypeScript 类型,减少重复代码。

    type User = z.infer<typeof userSchema>;
    const user: User = { name: 'Alice', age: 25 };
    
    1
    2
  • 复用 schema:将常用的 schema 提取为独立的模块,方便复用。

    // schemas.ts
    export const addressSchema = z.object({
      street: z.string(),
      city: z.string(),
    });
    
    // user.ts
    import { z, addressSchema } from './schemas';
    const userSchema = z.object({
      name: z.string(),
      age: z.number().positive(),
      address: addressSchema,
    });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • 错误信息定制:使用 .describe() 方法为字段添加描述,提高错误信息的可读性。

    const userSchema = z.object({
      name: z.string().describe('用户姓名'),
      age: z.number().positive().describe('用户年龄'),
    });
    
    1
    2
    3
    4
  • 组合 schema:使用 .merge().extend() 方法组合多个 schema,提高代码的可维护性。

    const baseUserSchema = z.object({
      name: z.string(),
    });
    
    const detailedUserSchema = baseUserSchema.extend({
      age: z.number().positive(),
      address: addressSchema,
    });
    
    1
    2
    3
    4
    5
    6
    7
    8

🌙 7. 与 TypeScript 结合

Zod 与 TypeScript 深度集成,可以自动生成类型定义,并确保类型安全:

type User = z.infer<typeof userSchema>;
const user: User = { name: 'Alice', age: 25 };
1
2

通过以上内容,你可以快速上手 Zod 并在项目中应用其强大的数据校验功能。遵循这些最佳实践,可以帮助你编写更健壮、更易维护的代码。

🌙 8. 与 Prisma 结合

将 Zod 和 Prisma 结合使用可以显著提高数据校验和类型安全性的水平。Prisma 是一个现代的 ORM(对象关系映射)工具,而 Zod 是一个强大的 schema 声明和校验库。结合使用它们可以帮助你在数据层和应用层之间保持一致的类型定义和校验逻辑。以下是详细的步骤和示例,帮助你在项目中结合使用 Zod 和 Prisma。

🌙 1. 安装必要的依赖

首先,确保你已经安装了 Prisma 和 Zod:

npm install prisma zod @prisma/client
1
🌙 2. 初始化 Prisma

如果你还没有初始化 Prisma,可以按照以下步骤进行:

npx prisma init
1

这将创建一个 prisma 目录,并在其中生成一个 schema.prisma 文件。

🌙 3. 定义 Prisma 模型

prisma/schema.prisma 文件中定义你的数据模型。例如:

// prisma/schema.prisma
datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int     @id @default(autoincrement())
  name  String
  email String  @unique
  age   Int?
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
🌙 4. 生成 Prisma 客户端

运行以下命令生成 Prisma 客户端:

npx prisma generate
1
🌙 5. 定义 Zod Schema

为 Prisma 模型定义相应的 Zod schema。这有助于在应用层进行数据校验,并确保类型一致性。例如:

// schemas/userSchema.ts
import { z } from 'zod';

export const userSchema = z.object({
  id: z.number().int().positive().optional(),
  name: z.string().min(1, { message: 'Name is required' }),
  email: z.string().email({ message: 'Invalid email format' }),
  age: z.number().int().positive().optional().default(18),
});

export type User = z.infer<typeof userSchema>;
1
2
3
4
5
6
7
8
9
10
11
🌙 6. 使用 Zod 进行数据校验

在应用层使用 Zod 进行数据校验。例如,在创建用户时:

// services/userService.ts
import { PrismaClient } from '@prisma/client';
import { userSchema, User } from '../schemas/userSchema';

const prisma = new PrismaClient();

export const createUser = async (userData: unknown): Promise<User> => {
  // 校验输入数据
  const parsedUser = userSchema.parse(userData);

  // 使用 Prisma 创建用户
  const user = await prisma.user.create({
    data: parsedUser,
  });

  return user;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
🌙 7. 处理错误

确保在数据校验和数据库操作中处理可能的错误:

// services/userService.ts
import { PrismaClient, Prisma } from '@prisma/client';
import { userSchema, User } from '../schemas/userSchema';

const prisma = new PrismaClient();

export const createUser = async (userData: unknown): Promise<User> => {
  try {
    // 校验输入数据
    const parsedUser = userSchema.parse(userData);

    // 使用 Prisma 创建用户
    const user = await prisma.user.create({
      data: parsedUser,
    });

    return user;
  } catch (error) {
    if (error instanceof z.ZodError) {
      console.error('Validation error:', error.errors);
      throw new Error('Invalid input data');
    } else if (error instanceof Prisma.PrismaClientKnownRequestError) {
      console.error('Database error:', error.message);
      throw new Error('Database error');
    } else {
      console.error('Unexpected error:', error);
      throw new Error('Unexpected error');
    }
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
🌙 8. 最佳实践
  • 类型一致性:确保 Zod schema 和 Prisma 模型之间的类型一致,减少类型不匹配的问题。
  • 复用 schema:将常用的 schema 提取为独立的模块,方便复用。
  • 错误处理:在数据校验和数据库操作中进行详细的错误处理,提高代码的健壮性。
  • 文档和注释:为 schema 和服务函数添加详细的文档和注释,方便团队成员理解和维护代码。
🌙 9. 总结

通过结合使用 Zod 和 Prisma,你可以在应用层和数据层之间保持一致的类型定义和校验逻辑,从而提高代码的健壮性和可维护性。遵循上述步骤和最佳实践,可以帮助你在项目中高效地使用 Zod 和 Prisma。