@Millenial2020 I landed here looking for something else... and its a bit late...
However here's an answer, including how to resolve the issue: "type 'string' is not assignable to type 'PaymentType'" that you mention in a comment to the other answer in this thread:
Try using as const
:
// note the 'as const'
export const PAYMENT_TYPES = ['CHECK', 'DIRECT DEPOSIT', 'MONEY ORDER'] as const
// works great
export const zPaymentType = z.enum(PAYMENT_TYPES)
// these types are all equivalent
export type PaymentType = 'CHECK' | 'DIRECT DEPOSIT' | 'MONEY ORDER'
export type PaymentType_TypeScript = (typeof PAYMENT_TYPES)[number]
export type PaymentType_Zod = z.infer<typeof zPaymentType>
This is called a const assertion, added in TypeScript 3.4: see release notes for this feature.
as const
tells TypeScript that your array definition is a literal readonly tuple and that extra piece of information is what enables you to work with it with type definitions + zod's z.enum()
.
When you define an array of strings and provide no other information, TypeScript infers a "widened" type that encompasses all of the values. If you think about it, it has to assume your array is of type string[]
because you are free to manipulate the array and mutate its items to things that aren't one of 'CHECK', 'DIRECT DEPOSIT', or 'MONEY ORDER'.
The other answer suggests using enum
however you can search out articles on why TypeScript enums are "dangerous" or "broken". The as const
approach delivers a similar capability to enums in a more type-safe way... which also helps explain why a leading run-time type-checking library like zod chose to call this approach its official enum
type instead of the one built into the language (which you can use with z.nativeEnum()
).