Skip to content

Zod: TypeScript issue with default value for Zod enum validator #2427

@mchyll

Description

@mchyll

When generating Zod validators for an array of string enum values with a default value, TypeScript complains that the type of the generated default value variable (a string[]) is not assignable to the allowed enum values (an array of a union of string literals, e.g. ("A" | "B" | "C")[]).

How to reproduce

Given the attached OpenAPI schema and configs, Orval generates this:

/**
 * Generated by orval v7.13.1 🍺
 * Do not edit manually.
 * Zod enum issue
 * OpenAPI spec version: 0.1.0
 */
import * as zod from 'zod';

export const postEnumBodySomeEnumDefault = ["A"];

export const postEnumBody = zod.object({
  "some_enum": zod.array(zod.enum(['A', 'B', 'C'])).default(postEnumBodySomeEnumDefault)
})

TypeScript reports the following error:

src/testing/orval-issue-enum.ts:12:61 - error TS2769: No overload matches this call.
  Overload 1 of 2, '(def: ("A" | "B" | "C")[]): ZodDefault<ZodArray<ZodEnum<{ A: "A"; B: "B"; C: "C"; }>>>', gave the following error.
    Argument of type 'string[]' is not assignable to parameter of type '("A" | "B" | "C")[]'.
      Type 'string' is not assignable to type '"A" | "B" | "C"'.
  Overload 2 of 2, '(def: () => ("A" | "B" | "C")[]): ZodDefault<ZodArray<ZodEnum<{ A: "A"; B: "B"; C: "C"; }>>>', gave the following error.
    Argument of type 'string[]' is not assignable to parameter of type '() => ("A" | "B" | "C")[]'.
      Type 'string[]' provides no match for the signature '(): ("A" | "B" | "C")[]'.

12   "some_enum": zod.array(zod.enum(['A', 'B', 'C'])).default(postEnumBodySomeEnumDefault)
                                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~

openapi.json

{
  "openapi": "3.1.0",
  "info": {
    "title": "Zod enum issue",
    "version": "0.1.0"
  },
  "paths": {
    "/enum": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InputWithEnum"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Success"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "InputWithEnum": {
        "properties": {
          "some_enum": {
            "items": {
              "$ref": "#/components/schemas/EnumDefinition"
            },
            "type": "array",
            "default": [
              "A"
            ]
          }
        },
        "type": "object"
      },
      "EnumDefinition": {
        "type": "string",
        "enum": [
          "A",
          "B",
          "C"
        ]
      }
    }
  }
}

orval.config.ts

import { defineConfig } from "orval";

export default defineConfig({
  openapi: {
    input: {
      target: "./openapi.json",
    },
    output: {
      target: "./zod-validators.ts",
      client: "zod",
    },
  },
});

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "types": [
      "vite/client",
      "vite-plugin-svgr/client"
    ],
    "lib": [
      "ESNext",
      "DOM",
      "DOM.Iterable"
    ]
  },
  "include": [
    "orval.config.ts",
    "zod-validators.ts"
  ]
}

Environment

  • Orval: 7.13.1
  • TypeScript: 5.9.3

How to resolve

One possible solution is to inline the default value in the Zod validator and skip the default value variable alltogether. In our case we don't need this exported variable anyway, so maybe this could be a configurable option?

export const postEnumBody = zod.object({
  "some_enum": zod.array(zod.enum(['A', 'B', 'C'])).default(["A"])
})

Another possible fix is to make sure that the generated default variable is typed as an array of const strings, like so:

export const postEnumBodySomeEnumDefault = ["A" as const];

Metadata

Metadata

Assignees

No one assigned

    Labels

    zodZod related issue

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions