自定义处理器
zod-codepen 允许您注册自定义处理器来扩展或覆盖内置的序列化行为。
registerHandler()
typescript
function registerHandler(type: string, handler: SchemaHandler): void参数
type- 要处理的模式类型名称(如'string','custom')handler- 处理函数
SchemaHandler 类型
typescript
type SchemaHandler = (
schema: unknown,
ctx: SerializerContext,
) => string | undefined;
interface SerializerContext {
adapter: ZodAdapter;
options: Required<SerializeOptions>;
indent: (level?: number) => string;
serialize: (schema: unknown, indentLevel?: number) => string;
}基本用法
覆盖内置处理器
typescript
import { registerHandler, serialize } from '@zod-codepen/zod-v3';
import { z } from 'zod';
// 自定义字符串处理
registerHandler('string', (schema, ctx) => {
// 添加注释
return '/* custom string */ z.string()';
});
serialize(z.string());
// → '/* custom string */ z.string()'添加新类型处理器
typescript
// 处理自定义类型
registerHandler('myCustomType', (schema, ctx) => {
return 'z.custom(/* ... */)';
});SerializerContext
处理器接收一个上下文对象,提供以下功能:
ctx.adapter
访问当前适配器:
typescript
registerHandler('object', (schema, ctx) => {
// 获取模式定义
const def = ctx.adapter.getDef(schema);
// 获取类型名称
const type = ctx.adapter.getType(schema);
// 检查是否为 Zod 模式
const isZod = ctx.adapter.isZodSchema(someValue);
// ...
});ctx.options
访问格式化选项:
typescript
registerHandler('array', (schema, ctx) => {
const { indent, format, indentLevel } = ctx.options;
if (!format) {
return 'z.array(...)'; // 单行
}
// 格式化输出
return `z.array(\n${indent.repeat(indentLevel + 1)}...\n${indent.repeat(indentLevel)})`;
});ctx.indent()
生成缩进字符串:
typescript
registerHandler('object', (schema, ctx) => {
const indent1 = ctx.indent(1); // 当前级别 + 1
const indent2 = ctx.indent(2); // 当前级别 + 2
return `z.object({\n${indent1}key: value\n})`;
});ctx.serialize()
递归序列化嵌套模式:
typescript
registerHandler('array', (schema, ctx) => {
const def = ctx.adapter.getDef(schema);
const elementSchema = def.type || def.element;
// 递归序列化元素类型
const elementCode = ctx.serialize(elementSchema);
return `z.array(${elementCode})`;
});实际示例
带注释的对象
typescript
registerHandler('object', (schema, ctx) => {
const def = ctx.adapter.getDef(schema) as Record<string, unknown>;
const shape = typeof def.shape === 'function' ? def.shape() : def.shape;
if (!shape || Object.keys(shape).length === 0) {
return 'z.object({})';
}
const indent = ctx.indent(1);
const entries = Object.entries(shape)
.map(([key, value]) => {
const valueCode = ctx.serialize(value, ctx.options.indentLevel + 1);
// 添加字段注释
return `${indent}/** Field: ${key} */\n${indent}${key}: ${valueCode}`;
})
.join(',\n');
return `z.object({\n${entries}\n${ctx.indent()}})`;
});自定义验证器序列化
typescript
import { z } from 'zod';
// 假设有一个自定义验证器
const PhoneNumber = z.string().refine(
(val) => /^\+?[1-9]\d{1,14}$/.test(val),
{ message: 'Invalid phone number' }
);
// 注册处理器来识别它
registerHandler('string', (schema, ctx) => {
const def = ctx.adapter.getDef(schema) as Record<string, unknown>;
// 检查是否有特定的验证逻辑
const checks = def.checks as Array<Record<string, unknown>> || [];
const hasPhoneValidation = checks.some(c => {
// 检测电话号码验证
return c.message === 'Invalid phone number';
});
if (hasPhoneValidation) {
return 'PhoneNumber'; // 返回自定义标识符
}
// 回退到默认处理
return undefined;
});简化的枚举输出
typescript
registerHandler('enum', (schema, ctx) => {
const def = ctx.adapter.getDef(schema) as Record<string, unknown>;
const values = def.values as string[];
// 如果值少于等于3个,使用联合类型风格
if (values.length <= 3) {
return values.map(v => `'${v}'`).join(' | ');
}
// 否则使用标准枚举
return `z.enum([${values.map(v => `"${v}"`).join(', ')}])`;
});返回 undefined
当处理器返回 undefined 时,序列化器将使用内置处理器:
typescript
registerHandler('string', (schema, ctx) => {
const def = ctx.adapter.getDef(schema);
// 只处理特殊情况
if (isSpecialCase(def)) {
return 'z.special()';
}
// 其他情况使用默认处理
return undefined;
});处理器优先级
自定义处理器优先于内置处理器:
typescript
// 1. 首先检查自定义处理器
// 2. 如果返回 undefined,使用内置处理器
// 3. 如果没有匹配的处理器,返回 'z.unknown()'调试技巧
typescript
registerHandler('object', (schema, ctx) => {
const def = ctx.adapter.getDef(schema);
// 调试:打印模式结构
console.log('Object schema def:', JSON.stringify(def, null, 2));
// 返回 undefined 使用默认处理
return undefined;
});注意事项
- 类型安全 - 处理器接收
unknown类型,需要自行进行类型断言 - 递归处理 - 使用
ctx.serialize()处理嵌套模式 - 格式一致性 - 遵循
ctx.options中的格式设置 - 回退机制 - 返回
undefined让默认处理器接管