runtime-validator
TypeScript icon, indicating that this package has built-in type declarations

4.2.1 • Public • Published

MIT license npm version Build Status Coverage Status

Runtime type checking & validation

A light weight library to perform run-time type checking and field validation for TypeScript and JavaScript.

Features

  • Easy to learn and read. Simple and fast to extend.
  • Small lib. Optimised for tree shaking.
  • Use with either TypeScript OR JavaScript.
  • Detailed error reporting.
  • Creates Validator objects that are concise and composable.
    • Type check against compile-time types and interfaces.
    • Validate both run-time types and field value constraints.
    • Advanced: Apply transforms, data version upgrades ... to all or parts of your data.
  • Can validate a value and then emit the result as:
    • A valid value OR An exception
    • A Promise (rejects if invalid)
    • A success/fail boolean result (logs errors).
    • Create your own result type!

Applications

  • Validate function call arguments
  • Unit test assertions
  • Validate client or server side request/response payloads.
    • Can either filter out (tObject) or prevent (tObjectStrict) undefined fields.
  • Validate component properties (Vue)
  • Create a TypeScript Type Guard

Within an application, build a local library of composable validators that consistently check the types and values of all internal and external data structures.

Installation

npm i runtime-validator

OR

yarn add runtime-validator

Projects using < typescript@3.0.1 will need a polyfill for the unknown type, such as unknown-ts.

Examples

Typescript Example #1 - Runtime type checking

TypeScript only checks types at compile time not at run-time. The TypeScript project have excluded this from their stated goals, Type guards work, but are limited in that they circumvent type inference instead of working with it, and can be cumbersome to write.

This example demonstrates how to create a validator and then use it to check the schema of a parsed JSON object.

 
import {
  Validator, tObject, tString, tNumber, tBoolean, optional
} from 'runtime-validator'
 
interface Pet {
  name: string;
  species: string;
  age?: number;
  isCute?: boolean;
}
 
const petValidator: Validator<Pet> = tObject({
  name: tString(),
  species: tString(),
  age: optional(tNumber()),
  isCute: optional(tBoolean())
})
 
// Since `JSON.parse()` returns `any` we need to type check the result at run-time.
const json: any = JSON.parse('{"name":"Lyle", "age":15, "isCute":true}');
 
// Returns value if valid, throws exception if invalid
// Exeception example
// `Input: {"name":"Lyle","age":15,"isCute":true}
// Failed at input: the key 'species' is required but was not present`
const pet: Pet = petValidator.asException(json);
 
// resolve() if valid, reject() if invalid
const petPromise: Promse<Pet> = petValidator.asPromise(json);
 
// true if valid, false if invalid and logs error.
const isValid: boolean = petValidator.asSuccess(json);

JavaScript Example #2 - VueJS Object Field Validation

VueJS supports custom validation of component properties via a validator field defined on the property. The asSuccess modifier matches the call signature so we can use it to validate a Pet property on a component:

import { tObject, tString, tNumber, tBoolean, optional } from 'runtime-validator';
 
// Create a logger using NPM 'debug' library
import debug from 'debug';
const logger = debug('MyPet');
 
const vPet = tObject({
  name: tString(),
  species: tString(),
  age: optional(tNumber()),
  isCute: optional(tBoolean())
});
 
// VueJs component
export default {
  name: 'MyPet',
  props: {
    pet: {
      type: Object,
      required: true,
      validator: v => vPet.asSuccess(v, logger)
      // OR validator: vPet.asSuccessL(logger)
    }
  },
  ...
}

Example #3: Data Validation

  • oneOf() acts like an enum that restricts a field to limited set of values of equal type.
  • Validator.where() can specify custom data validation conditions.
const range = (min: number, max: number) =>
  tNumber().where(
    n => n >= min && n <= max,
    `expected a number between ${min} and ${max}`
  );
 
const species = oneOf("dog", "cat", "bird", "snake");
 
const petValidator = tObject({
  name: tString(),
  species,
  age: optional(range(0, 100)),
  isCute: optional(tBoolean())
});

Documentation

This library uses the combinator pattern from functional programming to build a Validator.

Validators can transform data objects with unknown structure into known and verified type and values.

Abbreviations:

  • v = a Validator instance.
  • v1 ... vN is a Validator sequence (array or argument list).
  • value = a constant or a value being validated.

Full API:

Primitive validators

Primitive validators check a single value matches a primitive type.

When executed they return a validation result (value or error) where the value will match the original primitive type.

Primitive Description Return Type
tString() Matches a string Validator<string>
tNumber() Matches a number Validator<number>
tBoolean() Matches a boolean Validator<boolean>
tFunction() Matches a function Validator<function>
tUndefined() Matches a undefined Validator<any>
tAny() Matches any type. Validator<any>
tUnknown() Matches any type. Validator<unknown>

Modifiers

Modifiers adapt a value or validator to match/ignore or allow nullable/optional values.

Modifiers Description
constant(value) Matches a constant string, number or boolean value
nullable(v) Matches null or a value matching v
optional(v) Matches undefined or a value matching v
succeed(value) Ignores input and always returns value.
fails(error) Ignores input and always fails with the error.
valueAt(path, value) Returns a specific field from within the value data structure.

Combinators

Combinators combine or wrapper validators to validate a complex type.

Combinator Description
tArray(v) Matches an array containing elements that all match validator v
tDict(v) Matches a dictionary having strings as keys and values that all match v
tuple([v1, ... vN]) Matches an array containing elements that match validators v1 ... vN in sequence
oneOf(v1, ... vN) Matches one of the validators v1 .. vN which must all return the same type.
union(v1, ... vN) Matches one of the validators v1 .. vN. Return type is a union of return types.
intersection(v1, ... vN) Matches all of the validators v1 .. vN. Return type is the intersection of return types.
withDefault(value, v) If v fails to match input, return a default value.
lazy(v) Supports validation of recursive types. See example below.

Example: Use lazy(v) to validate a recursive type:

const validator: Validator<Comment> = tObject({
  msg: tString(),
  replies: lazy(() => tArray(validator)) // self reference
});

Constraints

Constraints are just wrapper validators to add additional value conditions. Internally they use the Validator.where() method to add these constraints.

These are just a few common examples we've included in the library. You'll likely want to create your own, so check out src/constraints.ts for ideas.

Constraints Description
truthy() Matches any truthy value
falsy() Matches any falsy value
range(min, max) Matches a number value between min and max
chars(n) Matches a string of length n
charsMin(min) Matches a string of at least min characters
charsMax(max) Matches a string of no more than max characters
charsRange(min, max) Matches a string of between min and max characters
matches(pattern) Matches a string that matches the pattern
httpUrl() Matches a HTTP or HTTPS URL

Validation Execution

The following functions all internally call v.check(value) to check if a value is valid. v.asException(), v.asPromise(), v.asSuccess() adapt the output from v.check() for use in different programming contexts. If you need a validator function with a different behaviour or call signature, follow the same coding pattern and create your own!

Example: v.asSuccess is useful in a Vue property validator or in a TypeScript Type Guard.

Execute Validation Description
v.asException(value) Returns validated value. Throws an exception if invalid.
v.asString(value) Returns null if valid or error if invalid.
v.asPromise(value) Returns a Promise that is resolved to the validated value or rejected with the error.
v.asSuccess(value,logger) If valid returns true, if invalid returns false and logs error. logger defaults to console.error
v.asSuccessL(logger) Injects the logger early, returning a new asSuccess(value) validator function.
v.check(value) Returns a CheckResult. Use to create a custom asXXX().

Validation Adaptors

Adaptors can transform a Validator to into a new Validator that when executed will adapt the validation Result. See the documentation on these methods in Validator classes for examples.

Adaptors Description
v.where(f(value),error) If f(value) is false, emits error. Used to create Constraints.
v.map(value => f(value)) Transforms a validated value to a new value.
v1.andThen(f(value) => v2) andThen() can conditionally chain together validator sequences.

Acknowledgements

This library owes thanks to:

Package Sidebar

Install

npm i runtime-validator

Weekly Downloads

124

Version

4.2.1

License

MIT

Unpacked Size

322 kB

Total Files

23

Last publish

Collaborators

  • tohagan