接口加了 nickname 字段,schema 和 interface 都动了,但只改了 schema 里的可选标记。编译通过,运行时 zod 把合法请求判成 400,一天拦了三百多次。日志里能对上时间点,这种反而好排。
schema 和 interface 是两份独立定义,编译器不会比对它们是否一致。类型只在编译期存在,运行时按 schema 校验,两边语义差一处就会在边界上拦掉合法数据。这一点先确认清楚,后面就不用反复试。
const UserSchema = z.object({ id: z.number(), nickname: z.string().optional() });
type User = z.infer<typeof UserSchema>;
const u: User = UserSchema.parse(input);
「zod 类型同步」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。
报错里带路径的,先去看那个路径在不在、权限对不对。同一份配置存在多处的,先确认改的是被加载的那一份。
处理上按这个顺序:让类型从 schema 推导 只保留一份定义;用 z.infer 导出类型 所有引用改到这一处;确实要手写 interface 就加一条双向断言;把断言放进单测 改一边漏一边立刻红。
结果对不对很好判断,改 schema 后类型自动跟着变 两份定义对不上的情况消失 400 的量回到零。
