runtime-validator
v4.2.1
Published
Runtime type checking and validation for TypeScript and JavaScript
Downloads
1,605
Maintainers
Readme
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.
- Can either filter out (
- 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 < [email protected]
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
= aValidator
instance.v1
...vN
is aValidator
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:
- TypeScript JSON type validation by Elias Mulhall
- Forked from this project with major changes.
- JsonValidator by Daniel van den Eijkel
- Type-safe JSON Validator by Wesley Merkel
- The Elm Json.Decode API