Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

476
Views
How to extract a single type from a Zod union type?

I'm using Zod and have an array containing different objects using a union. After parsing it I want to iterate through each item and extract it's "real" type / cut off the other types.

When checking for specific object properties, the following code works fine:

const objectWithNumber = zod.object({ num: zod.number() });
const objectWithBoolean = zod.object({ isTruthy: zod.boolean() });
const myArray = zod.array(zod.union([objectWithNumber, objectWithBoolean]));
const parsedArray = myArray.parse([{ isTruthy: true }, { num: 3 }]);

parsedArray.forEach((item) => {
  if ("num" in item) {
    console.info('objectWithNumber:', item);
    // TS knows about it => syntax support for objectWithNumber
  } else if ("isTruthy" in item) {
    console.info('objectWithBoolean:', item);
    // TS knows about it => syntax support for objectWithBoolean
  } else {
    console.error('unknown');
  }
});

An alternative would be using discriminated unions for this

const objectWithNumber = zod.object({ type: zod.literal("objectWithNumber"), num: zod.number() });
const objectWithBoolean = zod.object({ type: zod.literal("objectWithBoolean"), isTruthy: zod.boolean() });
const myArray = zod.array(zod.discriminatedUnion("type", [ objectWithNumber, objectWithBoolean ]));
const parsedArray = myArray.parse([{ type: "objectWithBoolean", isTruthy: true }, { type: "objectWithNumber", num: 3 }]);

parsedArray.forEach(item => {
  if (item.type === "objectWithNumber") {
    console.info('objectWithNumber:', item);
    // TS knows about it => syntax support for objectWithNumber
  } else if (item.type === "objectWithBoolean") {
    console.info('objectWithBoolean:', item);
    // TS knows about it => syntax support for objectWithBoolean
  } else {
    console.error('unknown');
  }
});

but I think I misunderstood this concept because there is just more code to write ( I can always add a shared property and inspect that one ). Any help on this is much appreciated :)

Are there better ways to identify a specific schema?

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

If I understood you correctly, your question boils down to "Why one should use discriminated unions instead of shared fields combined with optional fields". (zod.js just lifts this concept into runtime providing validation functionality). In your example, there is in fact no reason to use a discriminator (type property), because each object holds only a single non-optional property that is mutually exclusive between types and can be easily used to distinguish types. However, the main issue with this code is that the object names (or shapes/structures) do not communicate any intentions - that's why it's difficult to see the benefits of discriminated unions.

You can think of discriminated union as a type that describes a family of objects and provides an unified mechanism (in a form of a discriminator property) to identify them. This approach is less fragile than checking for the existence of some manually picked properties (like for instance num property). What if num for any reason becomes optional? Then your check for num existence will break. Another argument for discriminated union is to decrease the number of optional properties. Compare two following examples:

// shared and optional fields instead of discriminated union
type Vehicle = {
  name: string;
  combustionEngine?: PetrolEngine | DieselEngine;
  tankCapacity?: number;
  electricEngine?: ElectricEngine;
  batteryCapacity?: number;
}
type Vehicle = 
  | GasolineCar
  | ElectricCar

type = GasolineCar {
  kind: "gasolineCar";
  name: string;
  engine: PetrolEngine | DieselEngine;
  tankCapacity: number;
}

type ElectricCar  = {
  kind: "electricCar"
  name: string;
  engine: ElecticEngine;
  batteryCapacity: number;
}

The example with discriminated union produces much more descriptive code. You don't have to add multiple checks for optional fields - instead, just identify (as early as possible) type by discriminator and pass the object to a function/method accepting the more narrow type (GasolineCar or ElectricCar instead of Vehicle).

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!