Skip to content

Discriminated Unions and OneOf functionality not working #19

@alan-artbot

Description

@alan-artbot

Hello!

I have a repo demonstating the issue described below available here: https://github.com/alanbacon/zod-and-json-schema/tree/main


I have a use case for schemas with discriminated unions. As far as I understand it that means I can use the oneOf field in my JSON schema to define this:

export const apiDiscriminatedPostNodeSchema = {
  type: 'object',
  required: ['nodeType', 'parentNodeId'],
  properties: {
    // Common properties defined ONCE at the top level
    parentNodeId: {
      type: 'string',
    },
    value: {
      type: 'string',
    },
  },
  oneOf: [
    {
      // QUESTION Node - only discriminator and variant-specific properties
      properties: {
        nodeType: { const: 'QUESTION' },
        nodeSpecifics: {
          type: 'object',
          properties: {
            questionName: {
              type: ['string', 'null'],
            },
          },
          unevaluatedProperties: false,
        },
      },
    },
    {
      // DECISION Node
      properties: {
        nodeType: { const: 'DECISION' },
        nodeSpecifics: {
          type: 'object',
          properties: {
            notes: { type: ['string', 'null'] },
          },
          unevaluatedProperties: false,
        },
      },
    },
  ],
  unevaluatedProperties: false,
} as const;

the above should allow for an input object that looks like this:

const  input = {
  parentNodeId: '123',
  value: '456',
  nodeType: 'QUESTION',   // the type here defines what's allowed in the nodeSpecifics, and in this case they match
  nodeSpecifics: {
    questionName: 'What is your name?',
  }
}

or this:

const  input = {
  parentNodeId: '123',
  value: '456',
  nodeType: 'DECISION',   // the type here defines what's allowed in the nodeSpecifics, and in this case they match
  nodeSpecifics: {
    notes: 'some notes',
  }
}

to pass validation, but if the nodeType doesn't match the nodeSpecifics like in the below examples then the validation should fail:

const  input = {
  parentNodeId: '123',
  value: '456',
  nodeType: 'DECISION',   // the type here defines what's allowed in the nodeSpecifics, and in this case they do not match
  nodeSpecifics: {
    questionName: 'What is your name?',
  }
}

or

const  input = {
  parentNodeId: '123',
  value: '456',
  nodeType: 'QUESTION',   // the type here defines what's allowed in the nodeSpecifics, and in this case they do not match
  nodeSpecifics: {
    notes: 'some notes',
  }
}

Also rather strangly: if the nodeType field is completly invalid the validation also still passes when it should not.

const  input = {
  parentNodeId: '123',
  value: '456',
  nodeType: 'INVALID', // the type here defines what's allowed in the nodeSpecifics, the node type is completely invalid
  nodeSpecifics: {
    notes: 'some notes',
  }
}

Could you please take a look and let me know if im doing something incorrectly, or if there is some kind of work around.

Thanks


P.S

I also have a secondary question regarding the output type of the schema created by the convertJsonSchemaToZod function:

It appears to me that I need to cast the input JSON schema to type any in order for the convertJsonSchemaToZod to accept the type of the argument.

This results in a zod schema of type z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>. Wheras it would great if the types were a little tighter than this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions