T
TanStack6mo ago
stormy-gold

React hook to extract errors?

I got the following hook, I'm not sure how to properly take the message for StandardSchema errors, any insight would be great! We basically always use either string OR zod for validators.
const useFormatErrors = (errors: unknown[]): string[] => {
return errors.map((error) => {
if (typeof error === "string") {
return error;
}
if (error && typeof error === "object" && "message" in error) {
return error.message as string;
}
throw new Error("Unknown error type");
});
};
const useFormatErrors = (errors: unknown[]): string[] => {
return errors.map((error) => {
if (typeof error === "string") {
return error;
}
if (error && typeof error === "object" && "message" in error) {
return error.message as string;
}
throw new Error("Unknown error type");
});
};
2 Replies
stormy-gold
stormy-goldOP6mo ago
In my form as an example, sometimes standard schema returns errors in a structure like:
[
[
{
"code": "too_small",
"minimum": 1,
"type": "string",
"inclusive": true,
"exact": false,
"message": "Required",
"path": [
"purchaseOrderLineItems",
1,
"quantity"
]
}
]
]
[
[
{
"code": "too_small",
"minimum": 1,
"type": "string",
"inclusive": true,
"exact": false,
"message": "Required",
"path": [
"purchaseOrderLineItems",
1,
"quantity"
]
}
]
]
Other times:
[
{
"code": "too_small",
"minimum": 1,
"type": "string",
"inclusive": true,
"exact": false,
"message": "Required",
"path": [
"purchaseOrderLineItems",
0,
"lineItemCost"
]
}
]
[
{
"code": "too_small",
"minimum": 1,
"type": "string",
"inclusive": true,
"exact": false,
"message": "Required",
"path": [
"purchaseOrderLineItems",
0,
"lineItemCost"
]
}
]
I think depending on if the item is within an array it'll nest it in another array? Confused if there's a sort of handler already for this? This is what I'm doing now, seems to be working fine though not sure if there's a different recommended way:
const useFormatErrors = (errors: unknown[]): string[] => {
return errors.map((error) => {
if (typeof error === "string") {
return error;
}
if (!Array.isArray(error)) {
return getErrorFromObjectOrThrow(error);
}
if (Array.isArray(error)) {
return recursivelyGetStandardSchemaError(error);
}
throw new Error("Unknown error type");
});
};

const recursivelyGetStandardSchemaError = (error: unknown) => {
if (!Array.isArray(error)) {
return getErrorFromObjectOrThrow(error);
}
return recursivelyGetStandardSchemaError(error[0]);
};

const getErrorFromObjectOrThrow = (error: unknown) => {
if (error && typeof error === "object" && "message" in error) {
return error.message as string;
}
throw new Error("Unknown error type");
};
const useFormatErrors = (errors: unknown[]): string[] => {
return errors.map((error) => {
if (typeof error === "string") {
return error;
}
if (!Array.isArray(error)) {
return getErrorFromObjectOrThrow(error);
}
if (Array.isArray(error)) {
return recursivelyGetStandardSchemaError(error);
}
throw new Error("Unknown error type");
});
};

const recursivelyGetStandardSchemaError = (error: unknown) => {
if (!Array.isArray(error)) {
return getErrorFromObjectOrThrow(error);
}
return recursivelyGetStandardSchemaError(error[0]);
};

const getErrorFromObjectOrThrow = (error: unknown) => {
if (error && typeof error === "object" && "message" in error) {
return error.message as string;
}
throw new Error("Unknown error type");
};
xenial-black
xenial-black6mo ago
your approach sounds very similar to ours. I recommend using a type predicate for the message property:
interface Message {
message: string;
}
function hasMessage(input: unknown): input is Message {
return (input as Message)?.message !== undefined && typeof (input as Message).message === 'string';
}
interface Message {
message: string;
}
function hasMessage(input: unknown): input is Message {
return (input as Message)?.message !== undefined && typeof (input as Message).message === 'string';
}
looking back on this snippet, there seems to be an unnecessary check since the second condition overlaps the first

Did you find this page helpful?