Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inner discriminated union #1647

Closed
the-homeless-god opened this issue Dec 6, 2022 · 3 comments
Closed

Inner discriminated union #1647

the-homeless-god opened this issue Dec 6, 2022 · 3 comments
Labels
closeable? This might be ready for closing

Comments

@the-homeless-god
Copy link

the-homeless-god commented Dec 6, 2022

Issue statement:

As developer, I want to be able to create sub-unions under union without requirement to change parent-union key or within

Playground

Expected behaviour:

  • All tests are passed

Current behaviour:

/sandbox/node_modules/zod/lib/types.js:1457
            throw new Error("The discriminator value could not be extracted from all the provided schemas");
                  ^
Error: The discriminator value could not be extracted from all the provided schemas
    at Object.create (/sandbox/node_modules/zod/lib/types.js:1457:19)
    at Object.<anonymous> (/sandbox/src/index.ts:7:15)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Module.m._compile (/sandbox/node_modules/ts-node/src/index.ts:1597:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Object.require.extensions.<computed> [as .ts] (/sandbox/node_modules/ts-node/src/index.ts:1600:12)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at phase4 (/sandbox/node_modules/ts-node/src/bin.ts:579:12)

Repro code:

import test from "tape";
import { z } from "zod";

const carScheme = z.object({
  name: z.string(),
  settings: z.discriminatedUnion<"model", string, any>("model", [
    z.object({ model: z.literal("AI-controlled"), copilot: z.boolean() }),
    z.object({
      model: z.literal("Human-controlled"),
      copilot: z.literal(false)
    }),
    z.discriminatedUnion<"network", string, any>("network", [
      z.object({
        model: z.literal("Human-controlled-2"),
        network: z.literal("Wi-Fi")
      }),
      z.object({
        model: z.literal("Human-controlled-2"),
        network: z.literal("Bluetooth")
      })
    ])
  ])
});

test("valid for 1", (t) => {
  t.true(
    carScheme.safeParse({
      name: "valid",
      settings: {
        model: "AI-controlled",
        copilot: true
      }
    }).success
  );
  t.end();
});

test("valid for 2", (t) => {
  t.false(
    carScheme.safeParse({
      name: "valid",
      settings: {
        model: "Human-controlled",
        copilot: false
      }
    }).success
  );
  t.end();
});

test("valid for 3", (t) => {
  t.false(
    carScheme.safeParse({
      name: "valid",
      settings: {
        model: "Human-controlled-2",
        network: "Bluetooth"
      }
    }).success
  );
  t.end();
});

test("valid for 4", (t) => {
  t.false(
    carScheme.safeParse({
      name: "valid",
      settings: {
        model: "Human-controlled-2",
        network: "Wi-fi"
      }
    }).success
  );
  t.end();
});
@maxArturo
Copy link
Contributor

Hi @Zimtir ! Take a look at #1618, its in some sort of WIP. I haven't had a lot of time to look into it, but if I do I'll integrate it into #1589.

@maxArturo
Copy link
Contributor

Hi @Zimtir ,

the following will work under the latest commit of #1618. Feel free to verify by checking out the commit and putting this in the playground.ts file, then running yarn play. Let me know if this solves your use case!

const carScheme = z.object({
    name: z.string(),
    settings: z.discriminatedUnion("model", [
      z.object({ model: z.literal("AI-controlled"), copilot: z.boolean() }),
      z.object({
        model: z.literal("Human-controlled"),
        copilot: z.literal(false),
      }),
      z.discriminatedUnion("network", [
        z.object({
          model: z.literal("Human-controlled-2"),
          network: z.literal("Wi-Fi"),
        }),
        z.object({
          model: z.literal("Human-controlled-2"),
          network: z.literal("Bluetooth"),
        }),
      ]),
    ]),
  });

  carScheme.parse({
    name: "valid",
    settings: {
      model: "AI-controlled",
      copilot: true,
    },
  });

  carScheme.parse({
    name: "valid",
    settings: {
      model: "Human-controlled",
      copilot: false,
    },
  });

  carScheme.parse({
    name: "valid",
    settings: {
      model: "Human-controlled-2",
      network: "Bluetooth",
    },
  });

  // note: this will not work
  carScheme.parse({
    name: "valid",
    settings: {
      model: "Human-controlled-2",
      network: "Wi-Fi",
    },
  });
  console.log("success");

@JacobWeisenburger
Copy link
Contributor

@the-homeless-god
Is the above answer satisfactory? Or do you have any questions?

I'd like to close this issue if there are no further questions.

@JacobWeisenburger JacobWeisenburger added the closeable? This might be ready for closing label Dec 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closeable? This might be ready for closing
Projects
None yet
Development

No branches or pull requests

3 participants