Skip to content

Latest commit

History

152 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Toreda

CIGitHub issues

GitHub package.json version (branch)GitHub Release Date

license

verify

Expressive, type-safe validation for TypeScript. Write rules that read like plain English — value.is.greaterThan(0).and.is.lessThan(100) — verify entire objects with schemas, and handle the edge cases you'd otherwise hand-roll: type checks, null handling, empty values, and more.

Sections

  1. Rulesets
    1. How to use Ruleset
    2. Reading results
    3. Built-in Rules
    4. lessThan
    5. greaterThan
    6. between
    7. equalTo
  2. Schemas
  3. Checks
  4. Rule Validators

Rulesets

Rulesets allow inlining of complex & reusable validation.

Ruleset<ValueT> is a generic collection of rules that perform custom verification. ValueT is the TypeScript type of the value to be verified.

// Create a ruleset using the expected type to be verifiedconstruleset=newRuleset<number>();// Get a 'value' object from ruleset used to create rules.constvalue=ruleset.value();

How to use Ruleset

  1. Create a const ruleset = new Ruleset<ValueT> where ValueT is the TypeScript type of the object or value you wish to verify.
  2. You now have an empty set of rules.
  3. Add a rule to the empty ruleset using ruleset.add(ruleset.value().must.be.equalTo('cheese'));

Reading results

ruleset.verify(input) is async and returns a Fate<VerifierResult> from @toreda/fate. Call ok() to determine the overall outcome, and inspect data for per-rule counts.

construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.be.greaterThan(10));constresult=awaitruleset.verify(50);if(result.ok()){// All rules passed.}else{// One or more rules failed. Details in result.data:// result.data.summary.counts -> {pass, fail, error, skip, total, ...}// result.data.failedMatchers -> names of matchers that failed.}

Chaining rules

Combine multiple conditions in a single statement using and / or after any matcher.

construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.is.greaterThan(0).and.is.lessThan(100));constresult=awaitruleset.verify(55);

Built-in Rules

Type Checks

type(typeName: string) — matches when the value is of the named built-in type.

  • value.is.type('string')
  • value.is.type('array')

match.type(typeName) and match.atLeastOneType(typeNames) — match one type, or any type from a list.

  • value.must.match.type('number')
  • value.must.match.atLeastOneType(['string', 'number'])

String Rules

  • value.is.type('type_name')
  • value.is.not.type('type_name')
  • value.is.an.html5Tag()

Some rules can be called using different phrases due to variations in the English language. In these situations, all "paths" to reach the function call produce the same result. The following produce the same result:

  • value.must.be.an.html5Tag()
  • value.is.an.html5Tag()

Comparison Rules

Invert any rule by using not before the helper. If is.greaterThan(110) is the helper, then use is.not.greaterThan(110).

  • value.is.equalTo(100)
  • value.is.greaterThan(110)
  • value.is.greaterThanOrEqualTo(110)
  • value.is.lessThan(110)
  • value.is.lessThanOrEqualTo(110)
  • value.is.between(0, 100)

Number Rules

  • value.is.divisibleBy(2) — value divides evenly by the argument.
  • value.is.even() — value is an even number.
  • value.is.odd() — value is an odd number.
  • value.is.integer() — value is an integer.
  • value.is.positiveInteger() — value is an integer > 0.
  • value.is.negativeInteger() — value is an integer < 0.
  • value.is.an.int() — value is an integer.
  • value.is.a.uint() — value is an unsigned integer (0 or greater).
// Validate that input is an even number divisible by 10.construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.is.even().and.is.divisibleBy(10));constresult=awaitruleset.verify(20);

Collection Rules

  • value.is.an.array() — value is an array.
  • value.is.empty() — value is empty.
  • value.is.iterable() — value supports iteration.
  • value.has.length.equalTo(1) — value length matches exactly.
  • value.has.length.greaterThan(1) — value length is above the argument.
  • value.has.length.lessThan(10) — value length is below the argument.
// Validate that string input is non-empty and at most 9 characters.construleset=newRuleset<string>();constvalue=ruleset.value();ruleset.add(value.is.not.empty().and.has.length.lessThan(10));constresult=awaitruleset.verify('cheese');

Contains Rules

Check array or collection contents. Available through value.contains or value.must.contain.

  • value.contains.oneOf(['a', 'b']) — contains at least one listed element.
  • value.contains.allOf(['a', 'b']) — contains every listed element.
  • value.contains.noneOf(['a', 'b']) — contains none of the listed elements.
  • value.contains.atLeast(2) — contains at least n elements.
  • value.contains.atMost(5) — contains at most n elements.
  • value.contains.exactly(3) — contains exactly n elements.
// Validate that input array contains 'red' or 'blue', but never 'green'.construleset=newRuleset<string[]>();constvalue=ruleset.value();ruleset.add(value.contains.oneOf(['red','blue']).and.contains.noneOf(['green']));constresult=awaitruleset.verify(['blue','yellow']);

Object Rules

  • value.must.haveProperty('id') — object has the named property.
  • value.must.havePropertyWithType('id', 'string') — object has the named property with the given type.
// Validate that input object has an 'id' property of type string.construleset=newRuleset<{id: string}>();constvalue=ruleset.value();ruleset.add(value.must.havePropertyWithType('id','string'));constresult=awaitruleset.verify({id: 'user-a97'});

Network Rules

  • value.is.an.ipv4addr() — value is a valid IPv4 address.
  • value.is.an.ipv6addr() — value is a valid IPv6 address.
// Validate that string input is a valid IPv4 address.construleset=newRuleset<string>();constvalue=ruleset.value();ruleset.add(value.is.an.ipv4addr());constresult=awaitruleset.verify('192.168.1.1');

Misc Rules

  • value.is.truthy() — value evaluates to a truthy value.

lessThan

// Validate whether number input is less than 0.construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.be.lessThan(0));// Tests input against all rules in ruleset.constresult=awaitruleset.verify(-99);
// Validate whether number input is not less than 0.construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.not.be.lessThan(0));// Tests input against all rules in ruleset.constresult=awaitruleset.verify(1);

greaterThan

// Validate whether number input is greater than 100.construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.be.greaterThan(100));// Tests input against all rules in ruleset.constresult=awaitruleset.verify(20000);

between

// Validate whether number input is between 0 and 5.construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.be.between(0,5));// Tests input against all rules in ruleset.constresult=awaitruleset.verify(3);

equalTo

// Value must be equal to thisconstruleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.be.equalTo(100));// Tests input against all rules in ruleset.constresult=awaitruleset.verify(100);

number values

// Validate whether number input is exactly 10.construleset=newRuleset<number>();constvalue=ruleset.value();ruleset.add(value.must.be.equalTo(10));// Tests input against all rules in ruleset.constresult=awaitruleset.verify(0);

string values

// Validate whether string input matches 'orange'.construleset=newRuleset<string>();constvalue=ruleset.value();ruleset.add(value.must.be.equalTo('orange'));// Tests input against all rules in ruleset.constresult=awaitruleset.verify('valuehere');

Schemas

Schema verifies whole objects field-by-field. Define the expected fields and allowed types once, then verify any input object against it. Supports optional fields via defaultValue, null types, nested child schemas, custom types, and output transformation.

import{Log}from'@toreda/log';import{Schema,typeSchemaData}from'@toreda/verify';interfaceUserDataextendsSchemaData<string|number|boolean>{name: string;age: number;active: boolean;}classUserSchemaextendsSchema<string|number|boolean,UserData,UserData>{constructor(base: Log){super({name: 'UserSchema',fields: [{name: 'name',types: ['string']},{name: 'age',types: ['number']},// Multiple types allowed per field, including 'null'.{name: 'active',types: ['boolean','null']}],base: base});}}constbase=newLog();constschema=newUserSchema(base);// Verify input object against the schema. Returns Fate<SchemaVerified>.constresult=awaitschema.verify({data: {name: 'Ana',age: 30,active: true},base: base});if(result.ok()){// All fields matched schema requirements.}

Use schema.verifyAndTransform({...}) to verify and map the verified fields onto a typed output object in one call.

Note:base accepts any LogLike logger. The example above uses @toreda/log, which is installed separately.

Checks

Checks are standalone verifier functions. Each returns a Fate result object: call ok() for the outcome, read data for the verified value, and errorCode() for the failure reason.

verifyArray

Check that value is a valid array.

constresult=verifyArray<string>(['a','b']);// result.ok() -> true, result.data -> ['a', 'b']

verifyArrayEmpty

Check that value is a valid array and empty.

constresult=verifyArrayEmpty([]);// result.ok() -> trueconstresult2=verifyArrayEmpty(['a']);// result2.ok() -> false

verifyBigInt

Check that value is a BigInt type, is an integer, and is finite.

constresult=verifyBigInt(BigInt(10));// result.ok() -> true, result.data -> 10n

verifyBoolean

Check that value has a boolean value true or false. Does not use type coercion.

constresult=verifyBoolean(false);// result.ok() -> true, result.data -> falseconstresult2=verifyBoolean(1);// result2.ok() -> false - no type coercion.

verifyStringId

Configurable validator for string-based ID values. Accepts a number of boundary condition parameters including min/max length, allow empty, allow nulls, auto-trim, etc. The first argument names the ID field in error codes.

constresult=verifyStringId('user_id','usr-a97x',{length: {min: 3,max: 32}});// result.ok() -> true, result.data -> 'usr-a97x'

verifyUrl

Configurable validator for URL values.

constresult=verifyUrl('https://www.toreda.com');// result.ok() -> true, result.data -> 'https://www.toreda.com'constresult2=verifyUrl('not a url');// result2.ok() -> false

Rule Validators

Rule validators check for a single condition using one or more function arguments and return a strict boolean value true or false.

Maths

powOf

Determine if value is a power of exponent.

Use cases

  • User uploaded image dimensions.
  • Texture sizes with size requirements, e.g. the power of 2 rule.
  • Cases where inputs may have non-number or non-finite values.
  • Performs type and bound checks on values before attempting to use math functions and returns false if the call would otherwise fail.

// Determine if 0 is a power of 1.constresult=powOf(0,1);
// Determine if 100 is a power of 10.constresult=powOf(100,10);

between

Determine if value is strictly greater than left AND less than right. Async — returns a Promise<boolean>.

// Result is TRUE - 15 is between 10 and 20.constresult=awaitbetween(10,15,20);

divisible

Determine if value divides evenly by by. Returns false for non-finite inputs or division by zero.

// Result is TRUE.constresult=divisible(10,5);

even / odd

Determine if value is an even or odd number.

// Result is TRUE.constresult=even(4);
// Result is TRUE.constresult=odd(3);

greaterThan / greaterThanEqualTo

Determine if left is greater than (or equal to) right.

// Result is TRUE.constresult=greaterThan(10,5);
// Result is TRUE.constresult=greaterThanEqualTo(10,10);

lessThan / lessThanEqualTo

Determine if left is less than (or equal to) right.

// Result is TRUE.constresult=lessThan(5,10);
// Result is TRUE.constresult=lessThanEqualTo(10,10);

equalTo

Determine if left is strictly equal to right. No type coercion.

// Result is FALSE - strict comparison, no coercion.constresult=equalTo(1,'1');

positiveInteger / negativeInteger

Determine if value is an integer greater than zero, or an integer less than zero.

// Result is TRUE.constresult=positiveInteger(5);
// Result is TRUE.constresult=negativeInteger(-5);


Numbers

isInt

Determine if value is an integer. Type guard for number.

// Result is TRUE.constresult=isInt(10);// Result is FALSE.constresult2=isInt(1.5);

isIntPos / isIntNeg

Determine if value is a positive integer, or a negative integer.

// Result is TRUE.constresult=isIntPos(3);
// Result is TRUE.constresult=isIntNeg(-3);

isUInt

Determine if value is an unsigned integer (0 or greater).

// Result is TRUE.constresult=isUInt(0);// Result is FALSE.constresult2=isUInt(-1);

isNumber

Determine if value is a number type. Returns false for NaN.

// Result is TRUE.constresult=isNumber(1.5);

isNumberFinite

Determine if value is a finite number. Returns false for NaN, Infinity, and -Infinity.

// Result is FALSE.constresult=isNumberFinite(Number.POSITIVE_INFINITY);

isPrimeInt

Determine if value is a prime number.

// Result is TRUE.constresult=isPrimeInt(7);

isBigInt

Determine if value is a BigInt type. Type guard for bigint.

// Result is TRUE.constresult=isBigInt(BigInt(10));


Collections

isArray

Determine if value is an array.

// Result is TRUE.constresult=isArray([]);// Result is FALSE.constresult2=isArray('string');

isArrayEmpty

Determine if value is an array and if so, whether it's empty. Does not throw. Returns false in all cases where value is not an array.

constvalue: string[]=['one'];// Result is FALSE.constresult=isArrayEmpty(value);
// Result is FALSE.constresult=isArrayEmpty(null);
// Result is FALSE.constresult=isArrayEmpty({});

TypeScript Equivalent

constvalue: unknown='081408';constresult=Array.isArray(value)&&value.length===0;

isArrayNotEmpty

Determine if value is an array containing at least one element. Returns false when value is not an array.

// Result is TRUE.constresult=isArrayNotEmpty(['one']);// Result is FALSE.constresult2=isArrayNotEmpty([]);

isIterable

Determine if value supports iteration (arrays, strings, Maps, Sets, generators, etc.).

// Result is TRUE.constresult=isIterable(['a','b']);// Result is FALSE.constresult2=isIterable(11);

empty

Determine if value is empty. Works with strings, arrays, and objects.

// Result is TRUE.constresult=empty('');// Result is FALSE.constresult2=empty(['a']);


Strings

isString

Determine if value is a string.

// Result is TRUE.constresult=isString('one');// Result is FALSE - no coercion of non-string values.constresult2=isString(111);

isStringNotEmpty

Determine if value is a string with a length of at least 1. Type guard for string.

// Result is TRUE.constresult=isStringNotEmpty('one');// Result is FALSE.constresult2=isStringNotEmpty('');

isHtml5Tag

Determine if value is a valid HTML5 tag name. Type guard for Html5Tag.

// Result is TRUE.constresult=isHtml5Tag('div');// Result is FALSE.constresult2=isHtml5Tag('not-a-tag');


Booleans & Misc

isBoolean

Determine if value is a strict boolean true or false. No type coercion. Type guard for boolean.

// Result is TRUE.constresult=isBoolean(false);// Result is FALSE - truthy, but not a boolean.constresult2=isBoolean(1);

isTruthy

Determine if value evaluates to a truthy value.

// Result is TRUE.constresult=isTruthy('one');// Result is FALSE.constresult2=isTruthy(0);

Package

@toreda/verify on NPM.

Source Code

@toreda/verify source on Github.

Contributions

Bug reports, comments, and pull requests are welcome.

Legal

License

MIT © Toreda, Inc.

Copyright

Copyright © 2019 - 2026 Toreda, Inc. All Rights Reserved.

Github

https://github.com/toreda

Website

https://www.toreda.com

About

Quick and simple function argument validation for TypeScript.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages