Z
Zod12mo ago
Scott Trinh

Preprocess (refine/transform) -> refine.transform.pipe

Here a slightly different suggestion: You could use a z.string().refine().transform().pipe(z.object({})) to make it a little more declarative and to rely on the Zod error reporting features in your "preprocessing" part.
3 Replies
Scott Trinh
Scott Trinh12mo ago
One potential caveat is that errors in piped schemas get reported for each schema in order, so you wouldn't get the int/min/max errors until the string was properly formatted.
addamsson
addamsson12mo ago
do you mean something like this?
const timeOfDayT = z
.string()
.superRefine((value, ctx) => {
if (value.includes(":") === false) {
ctx.addIssue(wrongFormatIssue);
return;
}
const [hoursStr, minsStr] = value.split(":");
if (!hoursStr || !minsStr) {
ctx.addIssue(wrongFormatIssue);
return;
}
const hours = parseInt(hoursStr);
const mins = parseInt(minsStr);
if (isNaN(hours) || isNaN(mins)) {
ctx.addIssue(wrongFormatIssue);
}
})
.transform((value) => {
const [hoursStr, minsStr] = value.split(":");
const hours = parseInt(hoursStr!);
const mins = parseInt(minsStr!);
return {
hours,
mins,
};
});
const timeOfDayT = z
.string()
.superRefine((value, ctx) => {
if (value.includes(":") === false) {
ctx.addIssue(wrongFormatIssue);
return;
}
const [hoursStr, minsStr] = value.split(":");
if (!hoursStr || !minsStr) {
ctx.addIssue(wrongFormatIssue);
return;
}
const hours = parseInt(hoursStr);
const mins = parseInt(minsStr);
if (isNaN(hours) || isNaN(mins)) {
ctx.addIssue(wrongFormatIssue);
}
})
.transform((value) => {
const [hoursStr, minsStr] = value.split(":");
const hours = parseInt(hoursStr!);
const mins = parseInt(minsStr!);
return {
hours,
mins,
};
});
i'm not sure I understand what pipe() does though oh i understand that's it, right?
const timeOfDayT = z
.string()
.superRefine((value, ctx) => {
if (value.includes(":") === false) {
ctx.addIssue(wrongFormatIssue);
return;
}
const [hoursStr, minsStr] = value.split(":");
if (!hoursStr || !minsStr) {
ctx.addIssue(wrongFormatIssue);
return;
}
const hours = parseInt(hoursStr);
const mins = parseInt(minsStr);
if (isNaN(hours) || isNaN(mins)) {
ctx.addIssue(wrongFormatIssue);
}
})
.transform((value) => {
const [hoursStr, minsStr] = value.split(":");
const hours = parseInt(hoursStr!);
const mins = parseInt(minsStr!);
return {
hours,
mins,
};
})
.pipe(
z.object({
hours: z.number().int().min(0).max(23),
mins: z.number().int().min(0).max(59),
})
);
const timeOfDayT = z
.string()
.superRefine((value, ctx) => {
if (value.includes(":") === false) {
ctx.addIssue(wrongFormatIssue);
return;
}
const [hoursStr, minsStr] = value.split(":");
if (!hoursStr || !minsStr) {
ctx.addIssue(wrongFormatIssue);
return;
}
const hours = parseInt(hoursStr);
const mins = parseInt(minsStr);
if (isNaN(hours) || isNaN(mins)) {
ctx.addIssue(wrongFormatIssue);
}
})
.transform((value) => {
const [hoursStr, minsStr] = value.split(":");
const hours = parseInt(hoursStr!);
const mins = parseInt(minsStr!);
return {
hours,
mins,
};
})
.pipe(
z.object({
hours: z.number().int().min(0).max(23),
mins: z.number().int().min(0).max(59),
})
);
Scott Trinh
Scott Trinh12mo ago
Exactly. You can move your min/max checking into your superRefine and then you don't even really need the z.object, but depending on your use case, it's nice to have the z.object for other things.