Runtypes
Runtime validation for static types
README
Runtypes
Safely bring untyped data into the fold
Runtypes allow you to take values about which you have no assurances and check that they conform to some type A. This is done by means of composable type validators of primitives, literals, arrays, tuples, records, unions, intersections and more.
Installation
- ```
- npm install --save runtypes
- ```
Example
Suppose you have objects which represent asteroids, planets, ships and crew members. In TypeScript, you might write their types like so:
- ```ts
- type Vector = [number, number, number]
- type Asteroid = {
- type: "asteroid"
- location: Vector
- mass: number
- }
- type Planet = {
- type: "planet"
- location: Vector
- mass: number
- population: number
- habitable: boolean
- }
- type Rank = "captain" | "first mate" | "officer" | "ensign"
- type CrewMember = {
- name: string
- age: number
- rank: Rank
- home: Planet
- }
- type Ship = {
- type: "ship"
- location: Vector
- mass: number
- name: string
- crew: CrewMember[]
- }
- type SpaceObject = Asteroid | Planet | Ship
- ```
If the objects which are supposed to have these shapes are loaded from some external source, perhaps a JSON file, we need to validate that the objects conform to their specifications. We do so by building corresponding Runtypes in a very straightforward manner:
- ```ts
- import { Boolean, Number, String, Literal, Array, Tuple, Record, Union } from "runtypes"
- const Vector = Tuple(Number, Number, Number)
- const Asteroid = Record({
- type: Literal("asteroid"),
- location: Vector,
- mass: Number,
- })
- const Planet = Record({
- type: Literal("planet"),
- location: Vector,
- mass: Number,
- population: Number,
- habitable: Boolean,
- })
- const Rank = Union(Literal("captain"), Literal("first mate"), Literal("officer"), Literal("ensign"))
- const CrewMember = Record({
- name: String,
- age: Number,
- rank: Rank,
- home: Planet,
- })
- const Ship = Record({
- type: Literal("ship"),
- location: Vector,
- mass: Number,
- name: String,
- crew: Array(CrewMember),
- })
- const SpaceObject = Union(Asteroid, Planet, Ship)
- ```
(See the examples directory for an expanded version of this.)
Now if we are given a putative SpaceObject we can validate it like so:
- ```ts
- // spaceObject: SpaceObject
- const spaceObject = SpaceObject.check(obj)
- ```
If the object doesn't conform to the type specification, check will throw an exception.
Error information
When it fails to validate, your runtype emits a ValidationError object that contains detailed information that describes what's the problem. Following properties are available in the object:
- name: Always "ValidationError"
- message: A string that summarizes the problem overall
- code: A [Failcode](https://github.com/pelotom/runtypes/blob/dcd4fe0d0bd0fc9c3ec445bda30586f3e6acc71c/src/result.ts#L12-L33) that categorizes the problem
- details: An object that describes which property was invalid precisely; only for complex runtypes (e.g. Record, Array, and the like)
If you want to inform your users about the validation error, it's strongly discouraged to rely on the format of message property in your code, as it may change across minor versions for readability thoughts. Instead of parsing message, you should use code and/or details property to programmatically inspect the validation error, and handle other stuff such as i18n.