Small library for creating schemas, that can validate and assert unknown data.
someone: Why not use valibot me: We have valibot at home... valibot at home:
pnpm add @jeppech/schema-ts
import * as v from '@jeppech/schema-ts'
const userdata = {
username: v.string(),
age: v.number(),
email: v.string(v.email()),
created_at: v.timestamp(),
deleted: v.optional(v.timestamp()),
have_you_heard_about_our_extended_warranty: v.bool()
}
type User = v.InferObject<typeof userdata>
/**
* The `User` type will have the following shape, and
* will following any changes made to the object above.
*
* type User = {
* username: string;
* age: number;
* email: string;
* created_at: Date;
* deleted: Option<Date>;
* have_you_heard_about_our_extended_warranty: boolean;
* }
*/
const form = new FormData() // from a request, eg. `await req.formData()`
const result = v.parse(form, userdata)
if (result.is_err()) {
// Contains a list of errors, WIP
console.log(result.unwrap_err())
} else {
// Returns the `User` object
const user = result.unwrap()
}
You can add your own Valuers
and Validators
, they are just simple functions.
A Valuer
is a function, which job is to assert, that the input value is of the type that we want, and return that type.
If this assertion fails, it must throw a ValidationError
.
The built-in Valuers takes a variadic number of Validators, which is used to validated the returned value, if needed.
Here's an example of a Valuer, that requires the property to be either admin
, user
or anonymous
. This could also be made as a Validator
, but using a Valuer
we are returned the concrete type.
const roles = ['admin', 'user', 'anonymous'] as const;
type UserRole = typeof roles[number]
export function role(...validators: v.Validator<UserRole>[]) {
return (value: unknown, field: string) => {
if (typeof value === 'string') {
if (roles.includes(value as UserRole)) {
return v.validate(value as UserRole, field, ...validators);
}
}
throw new v.ValidationError('expected a valid role', value, field);
};
}
const user = {
name: v.string(),
role: v.role()
}
type UserWithRole = v.InferObject<typeof user>
See src/valuers.ts for more examples
A Validator
is a function, that is passed as any other argument, besides the first, to the v.as(...)
function.
A Validators job is, as the name implies, to validate the input data. If a validation succeeds it must return void
/undefined
. If it fails, it must return a ValidationError.
As a Validator comes after a Valuer, we can expect an exact type as input data, for the function.
Here's an example of a Validator, that requires a timestamp to be in the future
function in_the_future(err = 'expected a timestamp in the future') {
return (value: Date, field: string) => {
const now = new Date();
if (value < now) {
return new ValidationError(err, value, field);
}
};
}
const notification = {
message: v.string(),
fire_at: v.timestamp(in_the_future())
}
type NotifyInFuture = v.InferObject<typeof notification>
See src/validators.ts for more examples