I am using a zod schema to validate an object with an enum field in it:
enum Colour {
red: 'Red',
blue: 'Blue',
}
const schema = z.object({
colour: z.nativeEnum(Colour),
});
I have input data coming from an api for the colour values as either 'red' or 'blue', and I want to check this with the above schema. However, the above schema's nativeEnum checks according the capitalized cases in the enum, not the enum properties:
enum Colour {
red: 'Red',
blue: 'Blue',
}
const schema = z.object({
colour: z.nativeEnum(Colour),
});
const rawInput1 = {
colour: 'red' // should be identified as valid
};
const parsedInput1 = schema.parse(rawInput1); // this fails
const rawInput2 = {
colour: 'Red' // should be identified as invalid
};
const parsedInput2 = schema.parse(rawInput2); // this passes
How can I make zod validate based the property in the enum instead of the value? And why is this happening?
The reason why I also want to parse the enum properties and I have defined the enum that way is because I want to parse the object and use the colour
variable to index its string value in the enum: Colour[parsedInput1.colour]
. This will not be possible if colour
is the string value.
You could get it to validate based on the keys using a regular .enum()
and extracting the enum keys with Object.keys()
:
enum Colour {
red = 'Red',
blue = 'Blue',
}
const keys = Object.keys(Colours) // ["red", "blue"]
const schema = z.object({
colour: z.enum(keys),
});
But the issue is that the type of keys
here is string[]
and not ["red", "blue"]
(even though this will be the actual value at runtime). So it will work, but you won't get the typescript validation...
With keyof typeof
it is possible to obtain a unions of the enum's keys
type KeyUnion = keyof typeof Colour // "red" | "blue"
So with a little bit of "lying to typescript" we can achieve the desired result by casting the keys
type:
const keys = Object.keys(Colours) as [keyof typeof Colour]
const schema = z.object({
colour: z.enum(keys),
});
This gets you something that works both at the type level and at runtime.
However do note that keys
is not actually of type [keyof typeof Colour]
, this is just a lie we tell typescript to obtain the correct inference.