I'm using VS Code with validation for a Zod schema for result of an API call which will either return:
{
"Appointment":
{
"Name": "etc..."
}
}
Or it will return a similarly shaped Error
object.
However, in the codebase that parses the result, VS Code warns of an error on either the .Appointment
or the .Error
attribute, citing that it may not exist.
Here's a minimal reproducible example:
import z from 'zod';
import { useState } from "react";
const appointmentSchema = z
.object({
Appointment: z.string(),
})
.or(
z.object({
Error: z.object({
Message: z.string(),
}),
}),
);
type AppointmentSchema = z.infer<typeof appointmentSchema>;
const twoObjects = [
{
Appointment: "test"
},
{
Error: {
Message: "test",
}
},
];
const random = async ():Promise<AppointmentSchema> => {
const rando = Math.floor(Math.random() * twoObjects.length);
return twoObjects[rando];
}
export default function View() {
const [appointment, setAppointment] = useState<AppointmentSchema>();
return (
<div>
<h1>Testing!!!!</h1>
<button
onClick={async () => {
const randObject = await random();
setAppointment(randObject);
}
}>Random Select</button>
{appointment && appointment.Appointment && <div>Appointment: {appointment.Appointment}</div>}
</div>
);
}
Is this an error on the editor's part, or am I using Zod (or TypeScript) incorrectly?
Thanks to the link to the TypeScript narrowing doc reference in the comment, I am able to narrow manually like this:
{appointment && typeof appointment === 'object' && 'Appointment' in appointment && (
<div>Appointment: {appointment.Appointment}</div>
)}
I can even utilize a zod object:
const appointmentOnlySchema = z.object({
Appointment: z.string(),
});
type AppointmentOnlySchema = z.infer<typeof appointmentOnlySchema>;
And replace 'object'
with typeof appointmentOnlySchema
(or even appointmentOnlySchema.safeParse(appointment).success
), but the editor is still complaining that the object might not contain the specified attribute.
Found a blog post that might help. Input still very welcome.
I think that the commentary above is correct that the issue isn't relevant to zod (nor React).
Also seems that checking if items === 'object'
is unnecessary.
Can just check for presence of item attribute:
type AppointmentSchema = { Appointment: string } | { Error: { message: string } };
function thing(appointment: AppointmentSchema): string {
if ('Appointment' in appointment)
return appointment && appointment.Appointment;
return "error";
}