colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
33.92k stars 1.18k forks source link

values of type number are not accepted when key of NativeEnum is specified as a number type #3759

Closed 052hide closed 1 month ago

052hide commented 1 month ago

version: v3.23.8

const STRING_KEY_ENUM = {
  ten: 10,
  twenty: 20,
} as const
z.nativeEnum(STRING_KEY_ENUM) // OK

const NUMBER_KEY_ENUM = {
  10: 10,
  20: 20,
} as const
z.nativeEnum(NUMBER_KEY_ENUM) // Error: Argument of type '{ readonly 10: 10; readonly 20: 20; }' is not assignable to parameter of type 'EnumLike'.

const NUMBER_WITH_QUOTE_KEY_ENUM = {
  '10': 10,
  '20': 20,
} as const
z.nativeEnum(NUMBER_WITH_QUOTE_KEY_ENUM) // Error: Argument of type '{ readonly '10': 10; readonly '20': 20; }' is not assignable to parameter of type 'EnumLike'.

While using numbers as keys might not be a common pattern, I would expect consistent behavior regardless of the key type. However, it appears that enums with number keys and stringified number keys lead to different results, which seems unintuitive.

sunnylost commented 1 month ago

Because enum members can't be numeric. What you're doing is similar to:

// this is invalid
enum e {
  10,
  20
}

A solution is to transform value into string:

const NUMBER_KEY_ENUM = {
  10: '10',
  20: '20',
} as const
z.nativeEnum(NUMBER_KEY_ENUM) 
052hide commented 1 month ago

A solution is to transform value into string: const NUMBER_KEY_ENUM = { 10: '10', 20: '20', } as const z.nativeEnum(NUMBER_KEY_ENUM)

Thank you for the suggestion.

However, since I am generating my code from an API schema, I am unable to change the value to a string. Do you have any suggestions for handling this scenario without enforcing the value as a string?

sunnylost commented 1 month ago

Could you provide more info about your scenario?