Validation
▶ Open in PlaygroundBasic Validation
Every schema has two validation methods: .validate(data) (synchronous) and .validateAsync(data) (asynchronous). Use .validate() by default — it returns a result with valid, errors, and the cleaned object. Switch to .validateAsync() only when your schema includes async validators or preprocessors. For object schemas, the result also includes a getErrorsFor() method for per-property error inspection — the flat errors array is deprecated on object schema results and will be removed in a future major version.
const result = UserSchema.validate({
name: 'Alice',
email: 'alice@example.com',
age: 30,
isActive: true
});
if (result.valid) {
console.log('Validated:', result.object);
} else {
// Use getErrorsFor() for per-property error inspection (see below)
const nameErrors = result.getErrorsFor(u => u.name);
console.log(nameErrors.errors); // ['...']
}
// Use validateAsync() when your schema has async validators/preprocessors
// const asyncResult = await UserSchema.validateAsync({ ... });Per-Property Errors (Recommended)
Use getErrorsFor() with a PropertyDescriptor selector to get errors for a specific field — perfect for showing inline form errors. This is the recommended way to inspect validation errors on object schemas and replaces the deprecated errors array on object schema validation results. It returns an object with isValid (boolean), errors (array of error strings), and seenValue (the value that was validated).
Pass { doNotStopOnFirstError: true } to .validate() to collect all errors at once, instead of stopping at the first failure:
const result = UserSchema.validate(
{ name: 'A', email: '', age: -5, isActive: true },
{ doNotStopOnFirstError: true }
);
// Get errors for a top-level property
const nameErrors = result.getErrorsFor(t => t.name);
console.log(nameErrors.isValid); // false
console.log(nameErrors.errors); // ['Name must be at least 2 characters']
console.log(nameErrors.seenValue); // 'A'
// Get errors for a nested property (e.g. address.city)
// const cityErrors = result.getErrorsFor(t => t.address.city);
// console.log(cityErrors.isValid); // true or false
// console.log(cityErrors.errors); // array of error stringsCustom Error Messages
▶ Open in PlaygroundEvery constraint method accepts an optional second argument for a custom error message. This lets you provide user-friendly messages instead of the default generic ones:
import { string, number, array } from '@cleverbrush/schema';
// String constraints with custom messages
const NameSchema = string()
.minLength(2, 'Name must be at least 2 characters')
.maxLength(100, 'Name cannot exceed 100 characters');
// Number constraints with custom messages
const AgeSchema = number()
.min(0, 'Age cannot be negative')
.max(150, 'Age seems unrealistic');
// Array constraints with custom messages
const TagsSchema = array(string())
.minLength(1, 'At least one tag is required')
.maxLength(10, 'No more than 10 tags allowed');Custom Validators
▶ Open in PlaygroundAdd custom synchronous or asynchronous validators to any schema. They receive the value and must return an object with valid (boolean) and optionally errors (array of { message: string }):
const EmailSchema = string()
.minLength(5, 'Email is too short')
.addValidator(async (value) => {
// Example: check against an API
if (value === 'taken@example.com') {
return {
valid: false,
errors: [{ message: 'This email is already registered' }]
};
}
return { valid: true };
});
// Use validateAsync() because the validator is async
const result = await EmailSchema.validateAsync('taken@example.com');
console.log(result.valid); // false
console.log(result.errors); // [{ message: 'This email is already registered' }]