Be Specific with Allowed Types
There are two possible solutions to this challenge.
One Solution: Use Unions & Literals
Literals can be used to represent numbers, strings, or booleans. They cannot represent objects.
We can use
z.infer to check our
Hovering in VS Code will show that we have either "private" or "public" as the options for
An Arguably Cleaner Solution: Enum
Using Zod enums with
z.enum does exactly the same thing under the hood:
We are able to use sugar syntax to parse literal values instead of having to use
This does not create an enum the way you think of it in TypeScript.
In TypeScript we would write:
Instead, a union type is created.
Using the same "hover to check" technique that we used above, we see the same thing despite the slightly different syntax: "private" or "public" in a string union.
Matt Pocock: This is the first solution. We've got z.union. Inside z.union we are passing an array. An array contains two possibilities. It contains a z.literal and another z.literal.
z.literals, you can use them to represent anything. They represent to you some...Any sort of literal values inside typescripts, rather. You can't use them to represent objects. You can use them to represent numbers or strings or booleans.
What you end up with is if we say
type formType = z.infer<typeof Form>, then we end up with private or public here. If I were to add another one to this in z.literal...What's the one down here, something-not-allowed. Then, what you get is this test would fail, of course, because we're specifically saying this thing is not allowed. We've now allowed it inside our union.
The other way to represent this, which is, I'd argue, a bit cleaner, is z.enum. This does exactly the same thing. It's just sort of under the hood. It's a sugar syntax for the other thing. I'm not sure you can parse it in z.literal here. Yeah.
You just parse in the literal values and it creates an enum for you. Rather, it doesn't create an enum as the way you think of it in TypeScript. It doesn't say PrivacyLevel private public like this. It doesn't do this. Instead, it creates a string literal type for you or a union type.
FormType = z.infer<typeof Form>. Here, again, even though we're using a slightly different syntax, it's producing the same thing, private or public in a string union.