Skip to content

jsDoc @discriminator kind tag generates z.union() instead of z.discriminatedUnion() #360

@alexkonst

Description

@alexkonst

Bug description

Hi. Thanks for the helpful tool.

When we using the jsdoc @discriminator tag to generate a schema, we get an incorrect result that differs from the expected one (z.union() instead of z.discriminatedUnion()).

According to the zod library's author (issue comment), there are no plans to fix the issue with union types working with discriminatedUnion. This behavior can be corrected for generated schema by explicitly using the .extend(Scheme.shape) method or an equivalent spread syntax (see example below).

Input

export type Foo = { a: string }
export type Bar = { b: number }

/**
 * @discriminator kind
 */
export type Item =
  | { kind: 'foo' } & Foo
  | { kind: 'bar' } & Bar

Expected output

// Generated by ts-to-zod
import { z } from 'zod'

export const fooSchema = z.object({ a: z.string() })
export const barSchema = z.object({ b: z.number() })

export const itemSchema = z.discriminatedUnion('kind', [
  z.object({ kind: z.literal('foo'), ...fooSchema.shape }),
  z.object({ kind: z.literal('bar'), ...barSchema.shape }),
])

Actual output

// Generated by ts-to-zod
import { z } from 'zod'

export const fooSchema = z.object({ a: z.string() })
export const barSchema = z.object({ b: z.number() })

export const itemSchema = z.union([
  z.object({ kind: z.literal('foo') }).and(fooSchema),
  z.object({ kind: z.literal('bar') }).and(barSchema),
])

Versions

  • Typescript: v5.8.3
  • Zod: v4.3.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions