14

I have this object:

const properties = [
  { value: "entire_place", label: "The entire place" },
  { value: "private_room", label: "A private room" },
  { value: "shared_room", label: "A shared room" },
] as const;

I need to use it with zod in order to

  1. Validate and parse my data on the backend
  2. Create a typescript union type with those possible values "entire_place" | "shared_room" | "private_room"

According to the zod documentation, i can do this:

const properties = [
  { value: "entire_place", label: "The entire place" },
  { value: "private_room", label: "A private room" },
  { value: "shared_room", label: "A shared room" },
] as const;

const VALUES = ["entire_place", "private_room", "shared_room"] as const;
const Property = z.enum(VALUES);
type Property = z.infer<typeof Property>;

However, I don't want to define my data twice, one time with a label (the label is used for ui purposes), and another without a label.

I want to define it only once using the properties object, without the VALUES array, and use it to create a zod object and infer the type from the zod object.

Any solutions how?

1 Answers1

17

In this case, I think I would infer the type for Property from properties directly. You can avoid repeating yourself with code like:

import { z } from "zod";

const properties = [
  { value: "entire_place", label: "The entire place" },
  { value: "private_room", label: "A private room" },
  { value: "shared_room", label: "A shared room" }
] as const;

type Property = typeof properties[number]["value"];
// z.enum expects a non-empty array so to work around that
// we pull the first value out explicitly
const VALUES: [Property, ...Property[]] = [
  properties[0].value,
  // And then merge in the remaining values from `properties`
  ...properties.slice(1).map((p) => p.value)
];
const Property = z.enum(VALUES);
Souperman
  • 5,057
  • 1
  • 14
  • 39
  • It works! Thank you. But is it possible that I pass the type to zod and zod automatically creates the enum from the possible values of the type? –  Sep 23 '22 at 11:07
  • Types don't exist at runtime. All of the type annotations that typescript uses to give you compiler checks will be stripped out and you'll just be left with Javascript. For `zod` to be able to do checks, it needs to have real world values. It's more of a TypeScript issue than a `zod` one. The type system lets you manipulate the types of runtime values with `typeof`, but you can't go in the other direction and manipulate runtime values with types. – Souperman Sep 24 '22 at 01:18