import { is, defineSchemas, formatErrors, type InferSchema } from 'ts-chas/guard';
// 1. Define schemas
const schemas = defineSchemas({
CreateUserRequest: is.object({
name: is.string.trim().min(1).max(100),
email: is.string.trim().toLowerCase().email.max(255),
age: is.number.int.between(0, 150).optional,
role: is.literal('admin', 'editor', 'viewer'),
tags: is.array(is.string.min(1)).max(10),
address: is.object({
street: is.string.min(1),
city: is.string.min(1),
zip: is.string.regex(/^\d{5}(-\d{4})?$/),
}),
}),
});
// 2. Infer the type
type CreateUserRequest = InferSchema<typeof schemas.CreateUserRequest>;
// 3. Parse incoming data
function handleCreateUser(body: unknown) {
const result = schemas.CreateUserRequest.parse(body);
if (result.isErr()) {
// Return structured validation errors to the client
return {
status: 400,
errors: formatErrors(result.error),
// {
// 'email': ['Expected string, but got number (123)'],
// 'role': ['Value "superuser" failed validation'],
// 'address.zip': ['Value "abc" failed validation'],
// }
};
}
const user = result.value;
// user.email is string — already trimmed and lowercased
// user.role is 'admin' | 'editor' | 'viewer'
return { status: 201, user };
}
// 4. Use assert when you want exceptions (e.g. in trusted internal code)
import { AggregateGuardError } from 'ts-chas/guard';
function mustBeValidUser(data: unknown): CreateUserRequest {
try {
return schemas.CreateUserRequest.assert(data);
} catch (e) {
if (e instanceof AggregateGuardError) {
throw new Error(`Invalid user data: ${e.message}`);
}
throw e;
}
}