Comprehensive error reporting with field-specific errors, custom messages, and structured error objects.
Core error interfaces and types for validation results.
interface ValidateError {
message?: string;
fieldValue?: Value;
field?: string;
}
type ValidateFieldsError = Record<string, ValidateError[]>;
type ValidateCallback = (
errors: ValidateError[] | null,
fields: ValidateFieldsError | Values
) => void;
type SyncErrorType = Error | string;Individual validation error containing details about what failed.
interface ValidateError {
/** Error message describing what validation failed */
message?: string;
/** The actual value that failed validation */
fieldValue?: Value;
/** The field name that failed validation */
field?: string;
}Usage Example:
const schema = new Schema({
name: { type: "string", required: true, min: 2 }
});
try {
await schema.validate({ name: "A" });
} catch (error) {
console.log(error.errors[0]);
// Output: {
// message: "name must be at least 2 characters",
// fieldValue: "A",
// field: "name"
// }
}Organized error mapping for easy field-level error handling.
type ValidateFieldsError = Record<string, ValidateError[]>;Usage Example:
const schema = new Schema({
name: { type: "string", required: true },
email: { type: "email", required: true },
age: { type: "number", min: 0 }
});
try {
await schema.validate({
name: "",
email: "invalid-email",
age: -5
});
} catch (error) {
console.log(error.fields);
// Output: {
// name: [{ message: "name is required", field: "name", fieldValue: "" }],
// email: [{ message: "email is not a valid email", field: "email", fieldValue: "invalid-email" }],
// age: [{ message: "age cannot be less than 0", field: "age", fieldValue: -5 }]
// }
// Access specific field errors
const nameErrors = error.fields.name;
const emailErrors = error.fields.email;
}Traditional callback pattern for handling validation results.
type ValidateCallback = (
errors: ValidateError[] | null,
fields: ValidateFieldsError | Values
) => void;Usage Examples:
// Success case
schema.validate(validData, (errors, fields) => {
if (errors) {
// Validation failed
console.log("Validation errors:", errors);
console.log("Field errors:", fields);
} else {
// Validation passed - fields contains validated data
console.log("Validation passed:", fields);
}
});
// Error case
schema.validate(invalidData, (errors, fields) => {
if (errors) {
// Handle each error
errors.forEach(error => {
console.log(`Field ${error.field}: ${error.message}`);
});
// Handle field-specific errors
Object.keys(fields).forEach(fieldName => {
const fieldErrors = fields[fieldName];
console.log(`${fieldName} has ${fieldErrors.length} errors`);
});
}
});Modern promise/async-await pattern with structured error objects.
Usage Examples:
// Promise with .catch()
schema.validate(data)
.then(validatedData => {
console.log("Success:", validatedData);
})
.catch(error => {
console.log("Validation failed");
console.log("Errors:", error.errors);
console.log("Fields:", error.fields);
});
// Async/await with try-catch
try {
const result = await schema.validate(data);
console.log("Validation passed:", result);
} catch (error) {
// error is an AsyncValidationError instance
console.log("Validation failed");
// Array of all errors
error.errors.forEach(err => {
console.log(`${err.field}: ${err.message}`);
});
// Field-organized errors
Object.entries(error.fields).forEach(([field, errors]) => {
console.log(`${field} has ${errors.length} error(s)`);
});
}Structured error class thrown by promise-based validation.
class AsyncValidationError extends Error {
errors: ValidateError[];
fields: Record<string, ValidateError[]>;
constructor(
errors: ValidateError[],
fields: Record<string, ValidateError[]>
);
}Usage Example:
try {
await schema.validate(invalidData);
} catch (error) {
if (error instanceof AsyncValidationError) {
console.log("Async validation error occurred");
console.log(`Total errors: ${error.errors.length}`);
console.log(`Fields with errors: ${Object.keys(error.fields).length}`);
}
}Configure error handling behavior through validation options.
interface ValidateOption {
suppressWarning?: boolean;
suppressValidatorError?: boolean;
first?: boolean;
firstFields?: boolean | string[];
error?: (rule: InternalRuleItem, message: string) => ValidateError;
}Control warning output during validation.
suppressWarning?: boolean;Usage Example:
// Suppress console warnings
await schema.validate(data, { suppressWarning: true });Control error throwing in custom validators.
suppressValidatorError?: boolean;Usage Example:
await schema.validate(data, { suppressValidatorError: true });Stop validation on the first error encountered.
first?: boolean;Usage Example:
try {
await schema.validate(data, { first: true });
} catch (error) {
// Only contains the first error found
console.log(`First error: ${error.errors[0].message}`);
}Stop validation on first error per field or specified fields.
firstFields?: boolean | string[];Usage Examples:
// Stop on first error for all fields
await schema.validate(data, { firstFields: true });
// Stop on first error for specific fields only
await schema.validate(data, {
firstFields: ["username", "email"]
});Provide custom error object creation function.
error?: (rule: InternalRuleItem, message: string) => ValidateError;Usage Example:
await schema.validate(data, {
error: (rule, message) => ({
message: `Validation failed: ${message}`,
field: rule.field,
fieldValue: rule.value,
timestamp: new Date().toISOString(),
ruleType: rule.type
})
});Common patterns for handling different error scenarios.
const displayFieldErrors = (fields) => {
Object.entries(fields).forEach(([fieldName, errors]) => {
const errorMessages = errors.map(err => err.message);
console.log(`${fieldName}: ${errorMessages.join(', ')}`);
});
};
try {
await schema.validate(data);
} catch (error) {
displayFieldErrors(error.fields);
}const aggregateErrors = (errors) => {
const summary = {
total: errors.length,
byField: {},
byType: {}
};
errors.forEach(error => {
// Group by field
if (!summary.byField[error.field]) {
summary.byField[error.field] = [];
}
summary.byField[error.field].push(error.message);
});
return summary;
};
try {
await schema.validate(data);
} catch (error) {
const summary = aggregateErrors(error.errors);
console.log(`Total errors: ${summary.total}`);
}const handleErrors = (error) => {
if (error.errors.length === 1) {
// Single error - show inline
const err = error.errors[0];
showInlineError(err.field, err.message);
} else {
// Multiple errors - show summary
showErrorSummary(error.fields);
}
};
try {
await schema.validate(data);
} catch (error) {
handleErrors(error);
}Handle errors in nested object validation.
Usage Example:
const schema = new Schema({
user: {
type: "object",
fields: {
profile: {
type: "object",
fields: {
name: { type: "string", required: true },
age: { type: "number", min: 0 }
}
}
}
}
});
try {
await schema.validate({
user: {
profile: {
name: "",
age: -5
}
}
});
} catch (error) {
// Nested field errors use dot notation
console.log(error.fields);
// Output: {
// "user.profile.name": [{ message: "user.profile.name is required", ... }],
// "user.profile.age": [{ message: "user.profile.age cannot be less than 0", ... }]
// }
}