Is it possible to define a Zod schema with a field that is possibly undefined
, but non-optional. In TypeScript this is the difference between:
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
As far as I can tell using z.union([z.string(), z.undefined()])
or z.string().optional()
results in the field being equivalent to IFoo2
.
I'm wondering if there is a way to specify a schema that behaves like IFoo1
.
Context / Justification
The reason that I might want to do something like this is to force developers to think about whether or not the field should be undefined
. When the field is optional, it can be missed by accident when constructing objects of that type. A concrete example might be something like:
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 }));
}
This is sort of a contrived example, but this occurs a lot in our codebase with React props. The idea with allowing the value to be undefined
but not optional is to force callers to specify that, for example, there was no preference specified vs picking yes or no. In the example I want an error when calling internal
because I want the caller to think about the email preference. Ideally the type error here would lead me to realize that I should ask for email preference as a parameter to signup
.
null
instead ofundefined
? I think it'd be also more explicit as these two values were made to distinguish between a variable not being set/initialised yet (undefined
) and a variable currently without a specific value (null
). – Masteratarmsundefined
to represent the absence of a configuration wherenull
is a possible configuration. If I passnull
in to mean “no preference” as well as a possible “preference isnull
“ then there’s a bit of overloading going on. I suppose I could use a bonafide optional type but I was hoping to simply useundefined
– Steel