vali-guard
TypeScript icon, indicating that this package has built-in type declarations

1.1.1 • Public • Published

vali-guard

npm npm bundle size

A somewhat flexible validation library with first-class TypeScript support.

Install

npm install vali-guard
yarn add vali-guard

Example

import * as guard from 'vali-guard';

const location: unknown = ...; // Some unvalidated input?

const schema = guard.object({
    country: guard.string(), // <- strings!
    zipCode: guard.number(), // <- numbers!
    city: guard.string(),
    address: guard.string(),
    companyName: guard.string().optional(), // <- optional fields!
    person: guard.object({ // <- nested objects!
        firstName: guard.string(),
        lastName: guard.string()
    })
});

if (schema.validate(location)) {
    console.log(location.person.lastName);
    //                  ^------^------------TypeScript won't complain! :)
}

API

BaseValidator

All validators that vali-guard provides inherit from the base validator.

interface BaseValidator {
    validate(subject: unknown, diagrnostics?: ValidationDiagnostics): boolean;
    optional(): Validator;
    nullable(): Validator;
}

.validate()

Validates a subject. This works the same for all validators.

Example using the string-validator:

import * as guard from 'vali-guard';
import { ValidationDiagnostics } from 'vali-guard';

const subject: unknown = ...;
const diagnostics: ValidationDiagnostics = {};

if (guard.string().validate(subject, diagnostics)) {
    // typeof subject === string
    // TypeScript infers that `subject` is a string within this block
} else {
    console.log(diagnostics.error); // "not string"
}

.optional()

Allows for undefined subjects.

import * as guard from 'vali-guard';

const subject: unknown = ...;

if (guard.string().optional().validate(subject)) {
    // typeof subject === string | undefined
}

.nullable()

Allows for null subjects.

import * as guard from 'vali-guard';

const subject: unknown = ...;

if (guard.string().nullable().validate(subject)) {
    // typeof subject === string | null
}

Validators

string()

Validates strings.

guard.string().validate('some string'); // returns true

number()

Validates numbers.

guard.number().validate(1337); // returns true

boolean()

Validates boolean values.

guard.boolean().validate(false); // returns true

nil()

Validates null values.

guard.nil().validate(null); // returns true

undef()

Validates undefined values.

guard.undef().validate(undefined); // returns true

fun()

Validates function values. Argument and return types cannot be inferred.

guard.fun().validate(() => undefined); // returns true
guard.fun().validate(class C {}); // returns true
guard.fun().validate(Math.sin); // returns true

unknown()

Validates any value. This is useful in object-validators when you want to allow for a field to exist.

guard.unknown().validate(someValue); // ALWAYS returns true for ANY input

value()

Validates a set of concrete primitive values. This function accepts an arbitrary amount of arguments.

guard.value('A').validate('A'); // returns true
guard.value('A').validate('B'); // returns false

guard.value('A', 'B').validate('B'); // returns true

guard.value('A', 1).validate(1); // returns true
guard.value('A', 1).validate('A'); // returns true

guard.value('A', 1, false, undefined, null, Symbol()).validate(null); // returns true
guard.value(1, 2, 3, '4', 5, 6, 7, 8, 9 /* and so on */).validate(4); // returns true

object()

Validates a an object. This validator can be composed of multiple validators of any kind.

guard.object({
    string: guard.string()
    number: guard.number()
    boolean: guard.boolean()
    nil: guard.nil()
    undef: guard.undef()
    unknown: guard.unknown()
    value: guard.value(1)
});

Object validators will reject all objects that contain fields that are not included in the schema:

const schema = guard.object({
    a: guard.string(),
});

schema.validate({
    a: 'some string',
    b: 42,
}); // returns false

Fields with unknown values are supported through the unknown-validator or the allowUnknown option:

const schema = guard.object({
    a: guard.string(),
    b: guard.unknown(),
});

// or

const schema = guard.object(
    {
        a: guard.string(),
    },
    {
        allowUnknown: true,
    }
);

schema.validate({
    a: 'some string',
    b: 42,
}); // returns true

The object-validator supports schemas for nested objects:

const schema = guard.object({
    a: guard.string(),
    b: guard.object({
        c: guard.number(),
    }),
});

schema.validate({
    a: 'some string',
    b: {
        c: 42,
    },
}); // returns true

oneOf()

Validates a value based on a set of validators. This validator takes two or more validators as function arguments.

const stringOrNumberValidator = guard.oneOf(guard.string(), guard.number());

stringOrNumberValidator.validate('some string'); // returns true
stringOrNumberValidator.validate(42); // returns true

array()

Validates arrays with a specific length and specific items. You should define the guard argument "as const", otherwise the order and length of the subject can not be infered.

guard.array([guard.string(), guard.number()] as const).validate(['some string', 42]); // returns true

guard.array([guard.string(), guard.number()] as const).validate('not an array'); // returns false
guard.array([guard.string(), guard.number()] as const).validate([]); // returns false
guard.array([guard.string(), guard.number()] as const).validate(['some string', 'some string']); // returns false
guard.array([guard.string(), guard.number()] as const).validate(['some string']); // returns false

guard.array([guard.number(), guard.number(), guard.number()] as const).validate([1, 2, 3]); // returns true

guard.array([guard.value(false)] as const).validate([false]); // returns true
guard.array([guard.value(false)] as const).validate([true]); // returns false

arrayOf()

Validates arrays with containing items of a type.

guard.arrayOf(guard.number()).validate([1, 2, 3, 5, 8, 13, 21]); // returns true

const stringOrNumberGuard = guard.oneOf(guard.number(), guard.string());
guard.arrayOf(stringOrNumberGuard).validate([1, '2', 3, '5', '8', '13', 21]); // returns true

const yesNoGuard = guard.value('yes', 'no');
guard.arrayOf(yesNoGuard).validate([]); // returns true
guard.arrayOf(yesNoGuard).validate(['yes']); // returns true
guard.arrayOf(yesNoGuard).validate(['yes', 'no']); // returns true
guard.arrayOf(yesNoGuard).validate(['yes', 'yes']); // returns true
guard.arrayOf(yesNoGuard).validate(['yes', 'no', 'oui']); // returns false

The length of subject arrays can be restricted with the minLength and maxLength functions:

const stringArrayGuard = guard.arrayOf(guard.string());

const maxLengthGuard = stringArrayGuard.maxLength(2);
maxLengthGuard.validate(['A']); // returns true
maxLengthGuard.validate(['A', 'B']); // returns true
maxLengthGuard.validate(['A', 'B', 'C']); // returns false

const minLengthGuard = stringArrayGuard.minLength(2);
minLengthGuard.validate(['A']); // returns false
minLengthGuard.validate(['A', 'B']); // returns true
minLengthGuard.validate(['A', 'B', 'C']); // returns true

const minLengthGuard = stringArrayGuard.minLength(2).maxLength(3);
minLengthGuard.validate(['A']); // returns false
minLengthGuard.validate(['A', 'B']); // returns true
minLengthGuard.validate(['A', 'B', 'C']); // returns true
minLengthGuard.validate(['A', 'B', 'C', 'D']); // returns false

assert()

You can have assert-like functionality by using the assert function. This function takes any guard and a value to validate. It will throw with a ValidationError when validation fails.

import * as guard from 'vali-guard';
import { assert, TypeError } from 'vali-guard';

const input: unknown = null;
const stringGuard = guard.string();

try {
    assert(stringGuard, input);
} catch (e) {
    console.log(e); // TypeError: not string
    console.log(e instanceof TypeError); // true
}

// from TypeScripts point of view, input is string here

Why

  • This project started out as proof-of-concept but turns out it is actually really useful.
  • Manual typecasting in TypeScript is not very satisfying.
  • For fun.

How

TypeScript has this really cool thing called user-defined type guards. Those in combination with fancy type inference make it possible for the validate function to act as a guard for types that are inferred from its input.

Package Sidebar

Install

npm i vali-guard

Weekly Downloads

1

Version

1.1.1

License

MIT

Unpacked Size

184 kB

Total Files

35

Last publish

Collaborators

  • lforst