Zod如何为必填字段设置undefined作为默认值
Zod 实现必填数字字段空默认值的最优方案
核心问题本质是表单控件的输入值类型和Zod期望的类型不匹配:数字输入框为空时,表单库拿到的返回值是空字符串''而非undefined,原生z.number()既不接受空字符串输入,也无法区分「用户未输入」和「输入值为0」的场景,才会出现强制要求设置默认值的问题。
实现方案
不需要修改字段的必填属性,也不需要给数字字段设置无意义的默认值(比如0),通过自定义校验逻辑兼容空输入场景即可,完全满足所有需求:
import { z } from 'zod'; // 可复用的必填数字字段校验规则 const requiredNumber = z .union([z.string(), z.number(), z.null(), z.undefined()]) .superRefine((val, ctx) => { // 识别所有空输入场景,触发必填校验 if (val === '' || val === null || val === undefined) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: '该字段为必填项', fatal: true }); return z.NEVER; } // 非空值校验是否为合法数字,转换为数字类型输出 const numVal = Number(val); if (isNaN(numVal)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: '请输入有效的数字' }); return; } return numVal; }); const schema = z.object({ host: z.string().default('Host'), // 其余字段正常配置默认值即可 port: requiredNumber // port字段无需设置default });
方案匹配的特性
- port字段为强必填:空字符串、null、undefined三类空输入都会直接触发校验失败,不会自动填充任何默认值
- 校验通过的port值一定是数字类型,符合类型要求
- 新增场景下表单默认值不需要配置port字段,或者显式设为
''即可,输入框默认展示为空,强制用户主动输入 - 编辑场景下直接传入接口返回的数字类型port值做回填,schema可正常识别无报错
避坑提醒
- 不要直接使用
z.coerce.number():该方法会把空字符串''强制转换为0,会绕过必填校验,出现空提交时port值被自动设为0的问题 - 不要为了兼容空输入把port设为
.optional():会导致空提交时port值为undefined也能通过校验,不符合必填要求 - 该逻辑可复用到所有非字符串类型的必填字段(比如日期、布尔值选择器等),只需要调整对应的值转换和校验规则即可,不需要为了表单交互给业务字段设置无意义的默认占位值。
内容的提问来源于stack exchange,提问作者knoefel
相关产品推荐
相关产品推荐

