Skip to main content

zod 的作用

zod 是为了解决什么问题

Zod 是一个强大的工具,用于在 TypeScript 和 JavaScript 中进行类型安全的数据验证和解析。通过声明式的方式定义数据结构和验证规则,Zod 可以帮助开发者确保数据的类型和形状符合预期,从而提高代码的可靠性和可维护性。

zod 有什么用

Zod 的主要功能确实是用于数据验证,但它不仅仅局限于此。Zod 提供了一些额外的特性,使其在数据处理和类型安全方面非常有用。以下是 Zod 的一些主要功能和用途:

1. 数据验证

Zod 的核心功能是验证数据的类型和结构。你可以定义复杂的数据结构,并确保传入的数据符合这些结构。

2. 类型推断

Zod 与 TypeScript 紧密集成,可以自动推断类型。这意味着你可以获得类型安全的验证,而无需手动编写类型声明。

const UserSchema = z.object({
name: z.string(),
age: z.number().min(18),
});

type User = z.infer<typeof UserSchema>; // 自动推断出 User 类型

3. 数据解析和转换

Zod 允许你在验证数据的同时,对数据进行解析和转换。例如,你可以将字符串解析为日期对象。

const DateStringSchema = z.string().transform((str) => new Date(str));

const date = DateStringSchema.parse('2023-07-01');
console.log(date); // 输出: Date 对象

4. 默认值和可选字段

Zod 支持为字段设置默认值,并处理可选字段。

const UserSchema = z.object({
name: z.string(),
age: z.number().default(18), // 默认值
email: z.string().optional(), // 可选字段
});

const user = UserSchema.parse({ name: 'Alice' });
console.log(user); // 输出: { name: 'Alice', age: 18 }

5. 组合和复用模式

Zod 允许你组合和复用模式,使得定义复杂的数据结构更加简洁和易于维护。

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

const UserSchema = z.object({
name: z.string(),
address: AddressSchema, // 复用 AddressSchema
});

const user = UserSchema.parse({
name: 'Alice',
address: {
street: '123 Main St',
city: 'Wonderland',
zipCode: '12345',
},
});

6. 自定义验证

Zod 允许你定义自定义的验证逻辑,以满足特定的业务需求。

const PasswordSchema = z.string().refine((val) => val.length >= 8, {
message: 'Password must be at least 8 characters long',
});

try {
PasswordSchema.parse('short');
} catch (e) {
console.error(e.errors); // 输出自定义错误消息
}

7. 错误处理

Zod 提供详细的错误消息,帮助你快速定位和修复数据验证的问题。

const UserSchema = z.object({
name: z.string(),
age: z.number(),
});

try {
UserSchema.parse({ name: 'Alice', age: 'not a number' });
} catch (e) {
console.error(e.errors); // 输出详细的错误信息
}

结论

虽然 Zod 的主要功能是数据验证,但它还提供了类型推断、数据解析和转换、默认值和可选字段、组合和复用模式、自定义验证和详细的错误处理等功能。这些特性使得 Zod 在确保数据类型安全和结构一致性方面非常强大和灵活。

"strip"的作用

在 Zod 中,"strip" 是一个选项,用于控制在解析对象时是否移除对象中未定义的额外字段。Zod 提供了三种策略来处理对象中的额外字段:

  1. "strip":移除对象中未定义的额外字段。
  2. "passthrough":保留对象中未定义的额外字段。
  3. "strict":如果对象中包含未定义的额外字段,则验证失败。

在你的示例中:

export const SiweInitInput: z.ZodObject<
{
address: z.ZodEffects<z.ZodString, string, string>;
token: z.ZodOptional<z.ZodString>;
},
'strip',
z.ZodTypeAny,
{
address: string;
token?: string | undefined;
},
{
address: string;
token?: string | undefined;
}
>;

中间的 "strip" 表示在解析 SiweInitInput 对象时,将移除所有未在模式中定义的额外字段。具体来说,如果传入的对象包含 addresstoken 以外的字段,这些字段将在解析过程中被移除。

示例

假设我们有如下模式定义:

const SiweInitInput = z
.object({
address: z.string().transform((val) => val.toLowerCase()),
token: z.string().optional(),
})
.strip();

然后我们验证一个包含额外字段的对象:

const input = {
address: '0x1234567890ABCDEF',
token: 'some-token',
extraField: 'this should be removed',
};

const parsed = SiweInitInput.parse(input);
console.log(parsed);

输出

{
address: "0x1234567890abcdef",
token: "some-token"
// extraField 已被移除
}

详细解释

  1. 定义模式

    • address 字段是一个字符串,并且在解析时将其转换为小写。
    • token 字段是一个可选的字符串。
  2. 使用 .strip()

    • 调用 .strip() 方法将模式配置为移除未定义的额外字段。
  3. 解析输入对象

    • SiweInitInput.parse(input) 解析输入对象 input,并移除 extraField 字段,因为它未在模式中定义。

总结

"strip" 选项在解析对象时非常有用,可以确保输出对象只包含模式中定义的字段,从而避免不必要的数据污染。如果你希望保留额外字段或严格验证对象的结构,可以使用 "passthrough""strict" 选项。

5 个部分是什么意思

这个定义看起来复杂,但我们可以将其拆分成几个部分来理解。Zod 对象模式的定义通常包含以下几个主要部分:

  1. 字段定义:对象中的字段及其类型。
  2. 额外字段处理策略:如何处理对象中未定义的额外字段。
  3. 基础类型:对象的基础类型。
  4. 输出类型:解析后的输出类型。
  5. 输入类型:解析前的输入类型。

让我们详细拆解你的定义:

export const SiweInitInput: z.ZodObject<
{
address: z.ZodEffects<z.ZodString, string, string>;
token: z.ZodOptional<z.ZodString>;
},
'strip',
z.ZodTypeAny,
{
address: string;
token?: string | undefined;
},
{
address: string;
token?: string | undefined;
}
>;

1. 字段定义

{
address: z.ZodEffects<z.ZodString, string, string>;
token: z.ZodOptional<z.ZodString>;
}
  • address: 定义为 z.ZodEffects<z.ZodString, string, string>,表示这是一个字符串类型的字段,并且有一些效果(例如转换或验证)。
  • token: 定义为 z.ZodOptional<z.ZodString>,表示这是一个可选的字符串类型字段。

2. 额外字段处理策略

'strip';
  • "strip":表示在解析对象时移除未定义的额外字段。 @

3. 基础类型

z.ZodTypeAny;
  • z.ZodTypeAny:表示对象的基础类型,这里表示对象可以包含任意类型的字段。

4. 输出类型

{
address: string;
token?: string | undefined;
}
  • { address: string; token?: string | undefined; }:表示解析后的输出类型。address 是字符串,token 是可选的字符串或 undefined。

5. 输入类型

{
address: string;
token?: string | undefined;
}
  • { address: string; token?: string | undefined; }:表示解析前的输入类型。address 是字符串,token 是可选的字符串或 undefined。

总结

  1. 字段定义:定义了 addresstoken 字段的类型和效果。
  2. 额外字段处理策略:使用 "strip" 移除未定义的额外字段。
  3. 基础类型:使用 z.ZodTypeAny 作为基础类型。
  4. 输出类型:解析后的输出类型为 { address: string; token?: string | undefined; }
  5. 输入类型:解析前的输入类型为 { address: string; token?: string | undefined; }

这五个部分共同定义了 SiweInitInput 对象的结构和行为。

chain_type: z.ZodLiteral<"ethereum">; ZodLiteral 是什么

ZodLiteral 是 Zod 提供的一种类型,用于定义一个固定的常量值。换句话说,ZodLiteral 类型只能接受一个特定的值,如果输入的值与该常量值不匹配,则验证失败。

在你的例子中:

chain_type: z.ZodLiteral<'ethereum'>;

这表示 chain_type 字段只能是字符串 "ethereum"。任何其他值(例如 "bitcoin""polkadot")都会导致验证失败。

示例

假设我们定义一个对象模式,其中 chain_type 字段是一个 ZodLiteral:

const MySchema = z.object({
chain_type: z.literal('ethereum'),
});

然后我们尝试验证一些输入对象:

const validInput = { chain_type: 'ethereum' };
const invalidInput = { chain_type: 'bitcoin' };

console.log(MySchema.safeParse(validInput)); // { success: true, data: { chain_type: "ethereum" } }
console.log(MySchema.safeParse(invalidInput)); // { success: false, error: ... }

解释

  • validInput:包含 chain_type 字段,并且其值为 "ethereum",验证通过。
  • invalidInput:包含 chain_type 字段,但其值为 "bitcoin",验证失败,因为 "bitcoin" 不是 "ethereum"

使用场景

ZodLiteral 非常适用于需要严格限定某个字段的值为特定常量的场景,例如:

  • 限定某个配置选项只能是某些特定值之一。
  • 表示枚举类型的一个特定值。
  • 确保某些字段在特定上下文中的唯一合法值。

组合使用

ZodLiteral 可以与其他 Zod 类型组合使用。例如,如果你想定义一个模式,其中某个字段可以是多个固定值之一,可以使用 z.union

const MySchema = z.object({
chain_type: z.union([z.literal('ethereum'), z.literal('bitcoin')]),
});

这表示 chain_type 字段可以是 "ethereum""bitcoin"

总结

ZodLiteral 是 Zod 中用于定义固定常量值的类型。通过使用 ZodLiteral,你可以确保某个字段只能是特定的值,从而提高数据的可靠性和一致性。