后端返回的数据里,status 字段是个数字,比如 1,在前端展示时需要转为“OK”、“Unread”这样的文案。如果直接在 Zod schema 中为每个字段添加 .transform() 来派生新属性,容易导致解析报错和类型混乱——Zod 会误以为输入数据中已存在该字段。 核心思路:先定义基础结
后端返回的数据里,status 字段是个数字,比如 1,在前端展示时需要转为“OK”、“Unread”这样的文案。如果直接在 Zod schema 中为每个字段添加 .transform() 来派生新属性,容易导致解析报错和类型混乱——Zod 会误以为输入数据中已存在该字段。
正确做法是先定义好基础的对象结构,待整个解析完成后再进行整体转换。这样派生字段仅出现在输出侧,不参与输入校验,既干净又安全。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
import { z } from 'zod';
export enum ReportMessageStatus {
UNKNOWN = 0,
OK = 1,
UNREAD = 2,
DELETED = 3,
}
function transformStatus(status: ReportMessageStatus): string {
switch (status) {
case ReportMessageStatus.OK: return 'OK';
case ReportMessageStatus.UNREAD: return 'Unread';
case ReportMessageStatus.DELETED: return 'Deleted';
default: return 'Unknown';
}
}
// 正确姿势:基础对象 + 整体 .transform()
export const ReportMessageSchema = z
.object({
id: z.string(),
name: z.string(),
status: z.nativeEnum(ReportMessageStatus),
})
.transform((val) => ({
...val,
statusLabel: transformStatus(val.status), // 派生属性,不会出现在输入中
}));
// 使用示例
const rawData = { id: '203923', name: 'best name', status: 1 };
const parsed = ReportMessageSchema.parse(rawData);
// 类型推导为:{ id: string; name: string; status: ReportMessageStatus; statusLabel: string; }
console.log(parsed.statusLabel); // "OK"
.transform() 必须挂在完整的 z.object() 实例之后,而非某个字段上——否则会因输入中不存在该字段而直接报错。statusLabel)只出现在解析后的输出类型中,输入校验阶段不可见,运行时与类型完全对齐。statusLabel),可组合 .omit({ statusLabel: true }) 生成提交专用的 schema。这种方式保留了 Zod 的强类型约束,同时灵活地为前端 UI 层添加语义字段。简单、可控、符合直觉。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述