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

如何让Zod实现类似TypeScript接口与实现类的强制约束效果

如何让Zod实现类似TypeScript接口与实现类的强制约束效果

我明白你的需求:你想让NotificationDataSchema扮演一个类似TypeScript接口的角色,强制所有继承它的子Schema(比如NewFollowerSchema)必须显式定义data字段,而不是继承基础Schema里的空对象。默认情况下Zod的extend方法会合并字段,空的data会被保留,所以不会报错,但我们可以通过一个小技巧实现你要的强制约束。

核心解决方案:用z.never()标记必须被覆盖的字段

我们可以把基础Schema里的data字段定义为z.never()——这个类型表示该字段不可能有任何有效值,如果子Schema不重写它,无论是TypeScript类型检查还是Zod的运行时验证都会直接报错,完美模拟“接口强制实现”的效果。

具体代码实现

首先重构你的基础Schema:

import { z } from "zod";

// 基础Schema:用z.never()强制子Schema必须重写data字段
export const NotificationDataSchema = z.object({
  type: z.string(),
  data: z.never(), // 关键:标记data为必须覆盖的字段
});

然后是正常实现的LikesMilestoneSchema(重写了data,完全没问题):

export const LikesMilestoneSchema = NotificationDataSchema.extend({
  type: z.literal('LikesMilestone'),
  data: z.object({
    count: z.number(),
  }),
});

现在如果NewFollowerSchema不定义data,立刻会触发报错:

// ❌ 报错:data的类型是never,无法匹配任何实际数据,TS类型检查也会提示错误
export const NewFollowerSchema = NotificationDataSchema.extend({
  type: z.literal('NewFollower'),
  // 没有定义data,此时data继承了z.never(),完全不可用
});

必须显式定义data才能通过验证:

// ✅ 正常工作:重写了data字段,符合约束
export const NewFollowerSchema = NotificationDataSchema.extend({
  type: z.literal('NewFollower'),
  data: z.object({
    followerId: z.string(),
    username: z.string(),
    // 这里可以根据需求定义任意字段
  }),
});

最后你的联合Schema和最终的NotificationSchema可以正常使用:

export const NotificationData = z.union([
  LikesMilestoneSchema,
  NewFollowerSchema,
]);

export const NotificationSchema = z.object({
  id: z.string(),
  isRead: z.boolean(),
  date: z.date(),
  data: NotificationData,
});

为什么这个方案有效?

  1. TypeScript层面约束:当子Schema不重写data时,z.infer<typeof NewFollowerSchema>会得到data: never的类型,任何试图给这个字段赋值的代码都会触发TS类型错误,强制你必须定义data。
  2. 运行时验证约束:Zod的never类型会拒绝任何输入值,所以如果有人不小心漏掉了data的定义,在验证数据时会直接抛出错误,避免无效数据流入前端。

替代方案:空联合类型z.union([])

如果你觉得z.never()不够直观,也可以用z.union([])来代替,它和z.never()的效果完全一致——空联合类型在TypeScript里就是never,同样能实现强制覆盖的约束。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:14:35