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?