You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Zod编写封装object与default方法的类型化辅助函数

Zod 类型安全辅助函数:返回带默认空对象的对象 Schema

问题分析

你需要创建一个辅助函数,接收 Zod object 方法的参数,返回已应用 .default({}) 的 Zod 对象,同时替换掉 any 类型,用泛型实现正确的类型约束。

解决方案

利用 Zod 内置的类型(ZodRawShape、ObjectParams、ZodObject)来约束泛型,实现类型安全的函数:

基础实现(保留原字段必填性)

这个版本严格保留你传入的字段约束,仅添加空对象默认值(注意:如果有必填字段,直接 parse 空对象会触发校验错误):

import { z, ZodRawShape, ZodObject, ObjectParams } from "zod";

function objectWithDefault<Shape extends ZodRawShape>(
  shape: Shape,
  params?: ObjectParams
): ZodObject<Shape> {
  // 用 as 断言是安全的,因为 .default() 不会改变 Schema 的结构类型
  return z.object(shape, params).default({}) as ZodObject<Shape>;
}

增强实现(自动转为可选字段)

如果需要默认空对象能通过校验,可以自动将所有字段转为可选类型:

import { z, ZodRawShape, ZodObject, ObjectParams, ZodTypeAny } from "zod";

// 定义将 Shape 中所有字段转为可选的类型
type OptionalShape<Shape extends ZodRawShape> = {
  [K in keyof Shape]: Shape[K] extends ZodTypeAny ? Shape[K].optional() : never;
};

function objectWithDefault<Shape extends ZodRawShape>(
  shape: Shape,
  params?: ObjectParams
): ZodObject<OptionalShape<Shape>> {
  // 将传入的每个 schema 转为可选
  const optionalShape = Object.fromEntries(
    Object.entries(shape).map(([key, schema]) => [key, schema.optional()])
  ) as OptionalShape<Shape>;
  
  return z.object(optionalShape, params).default({});
}

使用示例

// 基础实现的使用
const BaseUserSchema = objectWithDefault({
  name: z.string(), // 必填字段
  age: z.number().optional()
});

// 类型推断:z.infer<typeof BaseUserSchema> = { name: string; age?: number }
// BaseUserSchema.parse({}) // 会报错,因为 name 是必填项

// 增强实现的使用
const OptionalUserSchema = objectWithDefault({
  name: z.string(),
  age: z.number()
});

// 类型推断:z.infer<typeof OptionalUserSchema> = { name?: string; age?: number }
const user = OptionalUserSchema.parse({}); // 成功,user = {}

内容的提问来源于stack exchange,提问作者cubabit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 08:12:52