I am making a react application using vite, react hook form (7.54.1) and zod (3.24.1) whose main function is a multi step form. Now in my form schemas, I need to customize the default zod messages using refine()/superrefine() but these methods just aren't working even when I provide guaranteed true condition to trigger them.
hardcoded sample data
const data = {
"Expense": [
{
"accountingFieldCode": {
"fieldCode": "DETAIL_CURRENCY_NAME",
"fieldCodeName": "Currency Name",
"description": null
},
"accountingOutputName": "sdfds",
"defaultValueApplicable": "N",
"defaultValue": "",
"prefixValue": "",
"suffixValue": "",
"fieldCodeConcatRequired": "N",
"concatCharacter": "",
"fieldCodeToConcat": [
{
"fieldCode": "VENDOR_NAME",
"fieldCodeName": "Vendor Name",
"description": null
},
{
"fieldCode": "EMPLOYEE_GL_CODE",
"fieldCodeName": "Employee GL Code",
"description": null
}
],
"maxDataLength": 3
}
]
};
schema
const defineFieldLineSchema = z.object({
accountingFieldCode: z
.object({
fieldCode: z.string(),
fieldCodeName: z.string(),
description: z.string().nullable(),
}),
accountingOutputName: z.string().min(1, "Field is required"),
defaultValueApplicable: z.string(),
defaultValue: z.string().optional(),
prefixValue: z.string().optional(),
suffixValue: z.string().optional(),
fieldCodeConcatRequired: z.enum(["Y", "N"]),
concatCharacter: z.string(),
fieldCodeToConcat: z.object({
fieldCode: z.string(),
fieldCodeName: z.string(),
description: z.string().nullable(),
}).optional(),
maxDataLength: z.number(),
}).superRefine((data, ctx) => {
if (data.fieldCodeConcatRequired === "Y" && !data.fieldCodeToConcat) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "fieldCodeToConcat is required when fieldCodeConcatRequired is 'Y'",
path: ["fieldCodeToConcat"],
});
}
if (Array.isArray(data.fieldCodeToConcat)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "fieldCodeToConcat must be an object, not an array",
path: ["fieldCodeToConcat"],
});
}
})
The only error I keep getting is the default zod message "Expected object, received array" instead of "fieldCodeToConcat must be an object, not an array" or "fieldCodeToConcat is required when fieldCodeConcatRequired is 'Y'".
Any help or suggestion regarding this would be greatly appreciated.
I am making a react application using vite, react hook form (7.54.1) and zod (3.24.1) whose main function is a multi step form. Now in my form schemas, I need to customize the default zod messages using refine()/superrefine() but these methods just aren't working even when I provide guaranteed true condition to trigger them.
hardcoded sample data
const data = {
"Expense": [
{
"accountingFieldCode": {
"fieldCode": "DETAIL_CURRENCY_NAME",
"fieldCodeName": "Currency Name",
"description": null
},
"accountingOutputName": "sdfds",
"defaultValueApplicable": "N",
"defaultValue": "",
"prefixValue": "",
"suffixValue": "",
"fieldCodeConcatRequired": "N",
"concatCharacter": "",
"fieldCodeToConcat": [
{
"fieldCode": "VENDOR_NAME",
"fieldCodeName": "Vendor Name",
"description": null
},
{
"fieldCode": "EMPLOYEE_GL_CODE",
"fieldCodeName": "Employee GL Code",
"description": null
}
],
"maxDataLength": 3
}
]
};
schema
const defineFieldLineSchema = z.object({
accountingFieldCode: z
.object({
fieldCode: z.string(),
fieldCodeName: z.string(),
description: z.string().nullable(),
}),
accountingOutputName: z.string().min(1, "Field is required"),
defaultValueApplicable: z.string(),
defaultValue: z.string().optional(),
prefixValue: z.string().optional(),
suffixValue: z.string().optional(),
fieldCodeConcatRequired: z.enum(["Y", "N"]),
concatCharacter: z.string(),
fieldCodeToConcat: z.object({
fieldCode: z.string(),
fieldCodeName: z.string(),
description: z.string().nullable(),
}).optional(),
maxDataLength: z.number(),
}).superRefine((data, ctx) => {
if (data.fieldCodeConcatRequired === "Y" && !data.fieldCodeToConcat) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "fieldCodeToConcat is required when fieldCodeConcatRequired is 'Y'",
path: ["fieldCodeToConcat"],
});
}
if (Array.isArray(data.fieldCodeToConcat)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "fieldCodeToConcat must be an object, not an array",
path: ["fieldCodeToConcat"],
});
}
})
The only error I keep getting is the default zod message "Expected object, received array" instead of "fieldCodeToConcat must be an object, not an array" or "fieldCodeToConcat is required when fieldCodeConcatRequired is 'Y'".
Any help or suggestion regarding this would be greatly appreciated.
Issue is that superrefine() and refine() is checked only if the initial check is fulfilled. Meaning fieldCodeToConcat has to be an object first according to the condition
fieldCodeToConcat: z.object({
fieldCode: z.string(),
fieldCodeName: z.string(),
description: z.string().nullable(),
}).optional()
for fine grained validation, fieldCodeToConcat can be changed to a value that is expected to be true so that it goes on to refine() / superrefine() like below. The console log would get printed in this case.
const defineFieldLineSchema = z.object({
fieldCodeToConcat: z.union([
z.record(z.any()), // Accepts any object
z.array(z.record(z.any())) // Accepts an array of any objects
]),
})
.superRefine((data, ctx) => {
console.log("HELLO")
if (Array.isArray(data.fieldCodeToConcat)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "fieldCodeToConcat must be an object, not an array",
path: ["fieldCodeToConcat"],
});
}
})