Z
Zod10mo ago
Rhys

Rhys - const formSchema = z .object({ veh...

const formSchema = z
.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.boolean().optional(),
replacingReg: z.string(),
})
.refine((data) => data.replacing === true, {
message:
"Replacing registration is required if replacing and required are checked",
path: ["replacingReg"],
});
const formSchema = z
.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.boolean().optional(),
replacingReg: z.string(),
})
.refine((data) => data.replacing === true, {
message:
"Replacing registration is required if replacing and required are checked",
path: ["replacingReg"],
});
- Trying to make it so replacing is optional and if replacing is set to true then replacingReg needs to be required, otherwise its optional. Anyone got some advice 🙂
Solution:
If the flaky types from the refine approach is not a problem for you, it is probably the easier solution to maintain. By flaky types I am referring to the fact that you cannot do exhaustive checks with TS like you can with discriminated unions: ```ts // Refine approach const data = formSchema.parse(...);...
Jump to solution
3 Replies
Sikari
Sikari10mo ago
You can either do something like this:
const formSchema = z
.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.boolean().optional(),
replacingReg: z.string().optional(),
})
.refine((data) => data.replacing && data.replacingReg !== undefined, {
message:
"Replacing registration is required if replacing and required are checked",
path: ["replacingReg"],
});
const formSchema = z
.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.boolean().optional(),
replacingReg: z.string().optional(),
})
.refine((data) => data.replacing && data.replacingReg !== undefined, {
message:
"Replacing registration is required if replacing and required are checked",
path: ["replacingReg"],
});
Or you can utilize discriminated unions and use replacing as your discriminator:
const vehicleSchema = z.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.undefined(),
});

const replacingVehicleSchema = z.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.literal(true),
replacingReg: z.string(),
});


const formSchema = z.discriminatedUnion("replacing", [
vehicleSchema,
replacingVehicleSchema
]);
const vehicleSchema = z.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.undefined(),
});

const replacingVehicleSchema = z.object({
vehicleReg: z.string(),
depot: z.string(),
replacing: z.literal(true),
replacingReg: z.string(),
});


const formSchema = z.discriminatedUnion("replacing", [
vehicleSchema,
replacingVehicleSchema
]);
The discriminated unions approach will make you repeat the properties, however nothing would stop you from extracing the common properties to another variable:
const commonSchema = z.object({
vehicleReg: z.string(),
depot: z.string(),
});

// Above or
const commonProperties = {
vehicleReg: z.string(),
depot: z.string(),
} as const;

const normalSchema = z.object({
...commonSchema.shape, // or ...commonProperties
foo: z.string(),
replacing: z.undefined(),
});

const replacingSchema = z.object({
...commonSchema.shape, // or ...commonProperties
bar: z.number(),
replacing: z.literal(true),
});

const formSchema = z.discriminatedUnion("replacing", [
vehicleSchema,
replacingVehicleSchema
]);
const commonSchema = z.object({
vehicleReg: z.string(),
depot: z.string(),
});

// Above or
const commonProperties = {
vehicleReg: z.string(),
depot: z.string(),
} as const;

const normalSchema = z.object({
...commonSchema.shape, // or ...commonProperties
foo: z.string(),
replacing: z.undefined(),
});

const replacingSchema = z.object({
...commonSchema.shape, // or ...commonProperties
bar: z.number(),
replacing: z.literal(true),
});

const formSchema = z.discriminatedUnion("replacing", [
vehicleSchema,
replacingVehicleSchema
]);
Solution
Sikari
Sikari10mo ago
If the flaky types from the refine approach is not a problem for you, it is probably the easier solution to maintain. By flaky types I am referring to the fact that you cannot do exhaustive checks with TS like you can with discriminated unions:
// Refine approach
const data = formSchema.parse(...);

if (data.replacing) {
data.replacingReg // still string | undefined here
} else {
data.replacingReg // still string | undefined here
}
// Refine approach
const data = formSchema.parse(...);

if (data.replacing) {
data.replacingReg // still string | undefined here
} else {
data.replacingReg // still string | undefined here
}
// Discriminated union approach
const data = formSchema.parse(...);

if (data.replacing) {
data.replacingReg // now just string
} else {
data.replacingReg // now just undefined
}
// Discriminated union approach
const data = formSchema.parse(...);

if (data.replacing) {
data.replacingReg // now just string
} else {
data.replacingReg // now just undefined
}
Rhys
RhysOP10mo ago
Wow what an indepth response, thank you so much for the assistance @Sikari Will implement these now 🙏 Youre a genius! Worked first time, I tried the dsicriminated approach, felt the most readable and easily adjustable, thanks very much!
Want results from more Discord servers?
Add your server