Skip to content

jeppech/schema-ts

Repository files navigation

Validate unknown data

npm package version

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:

Install

pnpm add @jeppech/schema-ts

Usage

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()
}

Extending

You can add your own Valuers and Validators, they are just simple functions.

Valuer

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

Validator

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

Acknowledgement

Valibot

About

Validate some unknown data, with a few functions

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published