zod
zod copied to clipboard
enum of numbers
This code fails:
import { z } from "zod";
const Multipliers = [1, 2, 3, 4] as const;
const schema = z.enum(Multipliers);
With error
No overload matches this call.
Overload 1 of 2, '(values: readonly [string, ...string[]]): ZodEnum<[string, ...string[]]>', gave the following error.
Argument of type '[1, 2, 3, 4, 5, 6]' is not assignable to parameter of type 'readonly [string, ...string[]]'.
Type at position 0 in source is not compatible with type at position 0 in target.
Type 'number' is not assignable to type 'string'.
Overload 2 of 2, '(values: [string, ...string[]]): ZodEnum<[string, ...string[]]>', gave the following error.
Argument of type '[1, 2, 3, 4, 5, 6]' is not assignable to parameter of type '[string, ...string[]]'.
Type at position 0 in source is not compatible with type at position 0 in target.
Type 'number' is not assignable to type 'string'.ts(2769)
Is there any reason why z.enum only expects strings?
https://codesandbox.io/s/zod-number-union-4pqezv
This would be very useful for us at Ping
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Well it is staled but it's not "completed" :\
For anyone else running into this problem, this is how I worked around the limitation in z.enum:
import { z } from 'zod';
import type { ZodType } from 'zod';
export const LIMIT_OPTIONS = [10, 25, 50] as const;
export function numericEnum<TValues extends readonly number[]>(
values: TValues,
) {
return z.number().superRefine((val, ctx) => {
if (!values.includes(val)) {
ctx.addIssue({
code: z.ZodIssueCode.invalid_enum_value,
options: [...values],
received: val,
});
}
}) as ZodType<TValues[number]>;
}
const TestSchema = z.object({
property: numericEnum(LIMIT_OPTIONS),
});
export type Test = z.infer<typeof TestSchema>;
@colinhacks Would you be open to a PR to add number support to enums? I know it isn't a 1:1 with the TypeScript definition of an enum, but this is in practice much more akin to a union (that's even what it infers to) than it is an enum in the TypeScript sense.
Hey, would be nice to have that
I think we can at least re-open this issue
A work around is like z.union([z.literal(-1), z.literal(1)])
any official updates on this?
I think "Native enums" might help: https://zod.dev/?id=native-enums
Sample code:
import { z } from "zod";
const Multipliers = {
one: 1,
two: 2,
three: 3,
four: 4,
} as const;
const schema = z.nativeEnum(Multipliers);