错误处理
Zod 提供了全面的错误处理功能,帮助你处理验证过程中的错误。
基本错误处理
ts
import { z } from "zod";
const schema = z.string();
try {
schema.parse(42); // 抛出 ZodError
} catch (error) {
if (error instanceof z.ZodError) {
console.log(error.issues);
// [
// {
// code: "invalid_type",
// expected: "string",
// received: "number",
// path: [],
// message: "Expected string, received number"
// }
// ]
}
}
自定义错误消息
ts
// 在创建模式时设置错误消息
const User = z.object({
username: z.string({
required_error: "用户名是必需的",
invalid_type_error: "用户名必须是字符串",
}),
age: z.number({
required_error: "年龄是必需的",
invalid_type_error: "年龄必须是数字",
}),
});
// 使用 .refine 添加自定义验证和错误消息
const ageSchema = z.number()
.refine(n => n >= 0, {
message: "年龄不能为负数",
})
.refine(n => n <= 120, {
message: "年龄不能超过120岁",
});
错误格式化
ts
const schema = z.object({
name: z.string(),
age: z.number(),
email: z.string().email(),
});
try {
schema.parse({
name: 42,
age: "not a number",
email: "invalid-email",
});
} catch (error) {
if (error instanceof z.ZodError) {
// 扁平化错误消息
console.log(error.flatten());
// {
// formErrors: [],
// fieldErrors: {
// name: ["Expected string, received number"],
// age: ["Expected number, received string"],
// email: ["Invalid email"]
// }
// }
// 获取所有错误消息
console.log(error.errors);
// [
// { path: ["name"], message: "Expected string, received number" },
// { path: ["age"], message: "Expected number, received string" },
// { path: ["email"], message: "Invalid email" }
// ]
}
}
错误映射
ts
// 全局错误映射
const customErrorMap: z.ZodErrorMap = (issue, ctx) => {
if (issue.code === z.ZodIssueCode.invalid_type) {
if (issue.expected === "string") {
return { message: "这个字段必须是字符串" };
}
}
if (issue.code === z.ZodIssueCode.too_small) {
return { message: "值太小了" };
}
return { message: ctx.defaultError };
};
z.setErrorMap(customErrorMap);
// 特定模式的错误映射
const schema = z.string().transform((val) => val.toUpperCase(), {
errorMap: (issue, ctx) => ({
message: "转换失败:" + ctx.defaultError,
}),
});
异步验证错误
ts
const asyncSchema = z.string().refine(async (val) => {
const response = await fetch(`/api/check-username/${val}`);
return response.ok;
}, {
message: "用户名已被使用",
});
try {
await asyncSchema.parseAsync("username");
} catch (error) {
if (error instanceof z.ZodError) {
console.log(error.issues);
}
}
错误处理最佳实践
ts
// 1. 使用类型守卫
function isZodError(error: unknown): error is z.ZodError {
return error instanceof z.ZodError;
}
// 2. 创建错误处理工具函数
function handleZodError(error: unknown) {
if (isZodError(error)) {
return {
success: false,
errors: error.flatten().fieldErrors,
};
}
return {
success: false,
errors: { _errors: ["发生未知错误"] },
};
}
// 3. 在 API 路由中使用
async function handleRequest(data: unknown) {
try {
const validData = await schema.parseAsync(data);
// 处理验证后的数据
return { success: true, data: validData };
} catch (error) {
return handleZodError(error);
}
}
// 4. 组合多个验证
const combinedSchema = z.object({
user: User,
preferences: Preferences,
}).refine(
(data) => {
// 复杂的跨字段验证
return true;
},
{
message: "验证失败",
path: ["user", "preferences"], // 指定错误路径
}
);