使用非可选但可能未定义的字段指定 Zod 模式

Sou*_*man 20 typescript zod

是否可以使用可能undefined但非可选的字段来定义 Zod 模式。在 TypeScript 中,这是以下之间的区别:

interface IFoo1 {
  somefield: string | undefined;
}

interface IFoo2 {
  somefield?: string | undefined;
}

const schema = z.object({
  somefield: z.union([z.string(), z.undefined()]),
}); // Results in something like IFoo2
Run Code Online (Sandbox Code Playgroud)

据我所知,使用z.union([z.string(), z.undefined()])orz.string().optional()导致该字段相当于IFoo2.

我想知道是否有一种方法可以指定行为类似于IFoo1.

背景/理由

我可能想做这样的事情的原因是迫使开发人员思考该字段是否应该是undefined. 当该字段是可选的时,在构造该类型的对象时可能会意外丢失该字段。一个具体的例子可能是这样的:

interface IConfig {
  name: string;
  emailPreference: boolean | undefined;
}
enum EmailSetting {
  ALL,
  CORE_ONLY,
}

function internal(config: IConfig) {
  return {
    name: config.name,
    marketingEmail: config.emailPreference ? EmailSetting.ALL : EmailSetting.CORE_ONLY,
  }
}

export function signup(userName: string) {
  post(internal({ name: userName }));
}
Run Code Online (Sandbox Code Playgroud)

这是一个人为的示例,但这种情况在我们的 React props 代码库中经常发生。允许值是undefined但不是可选的想法是强制调用者指定,例如,没有指定首选项与选择“是”或“否”。在示例中,我希望在呼叫时出现错误internal,因为我希望呼叫者考虑电子邮件首选项。理想情况下,这里的类型错误会让我意识到我应该要求电子邮件首选项作为signup.

Gus*_*Bus 13

您可以使用该transform函数显式设置您感兴趣的字段。这有点繁琐,但它有效。

const schema = z
    .object({
        somefield: z.string().optional(),
    })
    .transform((o) => ({ somefield: o.somefield }));

type IFoo1 = z.infer<typeof schema>;
// is equal to { somefield: string | undefined }
Run Code Online (Sandbox Code Playgroud)