第十五节:Hook Schemas
Zod Schema 与类型验证

作者:小学子 📚 | 日期:2026年4月2日 | 第一阶段 · 模块一


# 第一阶段 · 模块一 · 第十五节:Hook Schemas

核心问题

什么是 Hook Schemas?Claude Code 如何定义 Hook 类型?Zod Schema 在 Hook 验证中的作用是什么?如何解决 Hook 循环依赖?


◇ 本节位置


        Claude Code 全局架构
        
        ┌─────────────────────────────────────────────────────────────────────┐
        │  核心层(core/)                                                    │
        │                                                                      │
        │  Hook Schemas ← 本节                                                │
        │  ├── Zod Schema 定义                                                │
        │  ├── 循环依赖解决                                                   │
        │  └── 类型安全                                                       │
        └─────────────────────────────────────────────────────────────────────┘
        


一、Hook Schemas 概述

1.1 什么是 Hook Schema

源码位置:`src/core/hooks/schemas.ts`

Hook Schema 使用 Zod 定义 Hook 的输入输出类型,用于类型验证和自动补全


        ┌─────────────────────────────────────────────────────────────────────┐
        │  Hook Schema 工作流程                                                │
        │                                                                      │
        │  Hook 定义 ──► Schema 验证 ──► 类型推断                            │
        │                  │                                                  │
        │             Zod 解析                                                │
        └─────────────────────────────────────────────────────────────────────┘
        

1.2 Zod 简介


        // Zod 示例
        
        import { z } from 'zod'
        
        // 定义 Schema
        const UserSchema = z.object({
          name: z.string(),
          age: z.number(),
          email: z.string().email()
        })
        
        // 验证
        const result = UserSchema.safeParse({
          name: 'John',
          age: 30,
          email: 'john@example.com'
        })
        

1.3 五问分析

问 1:为什么使用 Zod 而不是 TypeScript 类型?


        // TypeScript 类型:
        // - 编译时检查
        // - 运行时无效
        
        // Zod Schema:
        // - 运行时验证
        // - 可用于 API 验证
        // - 自动类型推断
        


二、Hook Schema 定义

2.1 基础 Hook Schema

源码位置:`src/core/hooks/schemas.ts`


        // Hook 输入输出 Schema
        
        const HookInputSchema = z.object({
          type: z.enum(['before', 'after', 'error']),
          context: z.object({
            sessionId: z.string(),
            userId: z.string().optional()
          }),
          payload: z.record(z.unknown())
        })
        
        const HookOutputSchema = z.object({
          success: z.boolean(),
          modifiedPayload: z.record(z.unknown()).optional(),
          error: z.string().optional()
        })
        

2.2 具体 Hook Schema


        // 特定 Hook 的 Schema
        
        export const preToolCallSchema = z.object({
          toolName: z.string(),
          args: z.record(z.unknown()),
          context: z.object({
            sessionId: z.string()
          })
        })
        
        export const postToolCallSchema = z.object({
          toolName: z.string(),
          args: z.record(z.unknown()),
          result: z.unknown(),
          context: z.object({
            sessionId: z.string()
          })
        })
        

2.3 Schema 组合


        // Schema 组合
        
        const combinedSchema = z.object({
          // 使用已有 Schema
          hookInput: HookInputSchema,
          
          // 内联定义
          metadata: z.object({
            timestamp: z.number(),
            source: z.string()
          })
        })
        


三、循环依赖解决

3.1 循环依赖问题


        ┌─────────────────────────────────────────────────────────────────────┐
        │  循环依赖示例                                                        │
        │                                                                      │
        │  Hook Schema ──► 需要引用 Hook 类型                                  │
        │       │                                                            │
        │       ▼                                                            │
        │  Hook 类型 ──► 需要引用 Hook Schema                                  │
        └─────────────────────────────────────────────────────────────────────┘
        

3.2 解决方案

源码位置:`src/core/hooks/lazySchema.ts`


        // 使用 Zod lazy 解决循环依赖
        
        import { z } from 'zod'
        
        // 使用 lazy 创建延迟引用
        const HookSchema: z.ZodType<Hook> = z.lazy(() =>
          z.object({
            type: z.string(),
            name: z.string(),
            handler: z.function(),  // 延迟定义
            schema: HookSchema  // 引用自己
          })
        )
        

3.3 类型导出


        // 类型导出
        
        type Hook = z.infer<typeof HookSchema>
        type HookInput = z.infer<typeof HookInputSchema>
        type HookOutput = z.infer<typeof HookOutputSchema>
        
        // 使用类型
        function registerHook(hook: Hook): void {
          // hook 已经被类型验证
        }
        


四、Schema 验证

4.1 验证函数


        // Hook 验证
        
        function validateHook(hook: unknown): Hook {
          const result = HookSchema.safeParse(hook)
          
          if (!result.success) {
            throw new Error(
              `Invalid hook: ${result.error.message}`
            )
          }
          
          return result.data
        }
        

4.2 自定义验证


        // 自定义验证规则
        
        const customSchema = z.object({
          name: z.string()
            .min(3, 'Name must be at least 3 characters')
            .max(50, 'Name must be at most 50 characters'),
          
          handler: z.function()
            .args(z.string())
            .returns(z.string())
        })
        

4.3 五问分析

问 1:Schema 验证会影响性能吗?


        // 性能影响:
        
        // 1. 启动时
        // - Schema 解析一次
        // - 影响很小
        
        // 2. 运行时
        // - Hook 调用时验证
        // - 可使用 safeParse 控制
        
        // 3. 优化方法
        // - 缓存验证结果
        // - 生产环境可跳过
        


五、思考题

思考题 1:Hook Schema 的最佳实践?**

答案


        // 最佳实践:
        
        // 1. 使用 Zod 原语
        // - string(), number(), boolean()
        // - 避免过度复杂
        
        // 2. 明确错误消息
        // - 提供有意义的错误提示
        
        // 3. 合理拆分
        // - 按功能拆分 Schema
        // - 便于复用
        
        // 4. 文档同步
        // - Schema 即文档
        // - 保持同步
        


思考题 2:如何处理复杂的嵌套 Schema?**

答案


        // 方法:
        
        // 1. 拆分
        // - 按层级拆分 Schema
        // - 逐层引用
        
        // 2. 使用递归
        // - Zod 支持递归定义
        // - 如 lazy()
        
        // 3. 使用 transform
        // - 简化数据结构
        // - 预处理输入
        



思考题 3:Hook Schema 的循环依赖如何解决?

答案


        // 循环依赖问题:
        
        // 问题:HookSchema 引用 Hook 类型,Hook 类型引用 HookSchema
        
        // 解决:使用 lazy()
        
        const HookSchema: z.ZodType<Hook> = z.lazy(() =>
          z.object({
            type: z.string(),
            name: z.string(),
            handler: z.function(),
            schema: HookSchema  // 延迟引用自己
          })
        )
        
        // 原理:
        // - lazy() 延迟求值
        // - 使用时才解析
        // - 避免编译时循环
        


思考题 4:如何验证复杂的嵌套 Schema?

答案


        // 嵌套验证策略:
        
        // 1. 分层验证
        // - 逐层验证
        // - 从内到外
        
        // 2. 自定义验证
        // - 使用 z.refine()
        // - 添加业务规则
        
        // 3. 错误收集
        // - 使用 z.safeParse()
        // - 收集所有错误
        
        // 4. 性能优化
        // - 缓存验证结果
        // - 跳过未变化部分
        

六、延伸阅读

资源说明
`src/core/hooks/schemas.ts`Hook Schema 定义
Zod 官方文档Schema 详细用法