Zodra

Enums and Unions

Define enumerations and discriminated unions

Enums and Unions

Enums

Enums define a fixed set of allowed values:

app/types/order_status.rb
Zodra.enum :order_status, values: %i[draft confirmed shipped delivered cancelled]

Using enums in types

Once defined, an enum becomes a field type:

app/types/order.rb
Zodra.type :order do
  uuid :id
  order_status :status       # required
  order_status? :old_status  # optional
end

Generated output

zodra/order_status.ts
export const OrderStatusSchema = z.enum([
  "draft", "confirmed", "shipped", "delivered", "cancelled"
]);

export type OrderStatus = z.infer<typeof OrderStatusSchema>;

Unions

Discriminated unions represent a value that can be one of several shapes, distinguished by a discriminator field:

app/types/payment_method.rb
Zodra.union :payment_method, discriminator: :type do
  variant :card do
    string :last_four, min: 4, max: 4
    string :brand
    string :expiry_month, min: 2, max: 2
    string :expiry_year, min: 4, max: 4
  end

  variant :bank_transfer do
    string :bank_name
    string :account_last_four, min: 4, max: 4
  end
end

Using unions in types

Zodra.type :order do
  uuid :id
  reference :payment_method
end

Generated output

zodra/payment_method.ts
export const PaymentMethodSchema = z.discriminatedUnion("type", [
  z.object({
    type: z.literal("card"),
    lastFour: z.string().min(4).max(4),
    brand: z.string(),
    expiryMonth: z.string().min(2).max(2),
    expiryYear: z.string().min(4).max(4),
  }),
  z.object({
    type: z.literal("bank_transfer"),
    bankName: z.string(),
    accountLastFour: z.string().min(4).max(4),
  }),
]);

export type PaymentMethod = z.infer<typeof PaymentMethodSchema>;

Discriminator

The discriminator option specifies which field distinguishes variants. Each variant name becomes the literal value of that field.

# discriminator: :type means each variant gets a `type` field
# variant :card → type: "card"
# variant :bank_transfer → type: "bank_transfer"

On this page