A poor man's runtime-only type checker
MIT License
RunRunTypes
is a simple runtime-only type checker. It's a fairly specific and simple library
and it might be for you if:
Well, if you belong to this small exclusive club, then Welcome!
Disclaimer: This is frankly a horrible idea that's not meant for real world stuff, but it's been quite fun to write.
You can install RunRunTypes
like any other npm package:
yarn add --dev runruntypes
# or
npm install --save-dev runruntypes
NOTE: It's recommended to not ship this package in production as it pulls in
@babel/parser
as a dependency, which is really not that small. It's fairly simple to stub out this library's API though.
RunRunTypes
consists of two easy to use functions, gen
and type
.
import { gen, type } from 'runruntypes';
The gen
function is used to attach a type signature to your function. Using this signature
you can constrain the arguments' types and the function's return type. The gen
function will
wrap your function and return one that performs the checks when called. A signature is basically
a Flow type annotation:
const fn = gen`
(string, number, number) => [string, number]
`((str, a, b) => [str, a + b])
fn('test', 1, 2) // returns: ['test', 3]
fn('test', 1) // error!
fn(1, 1, 1) // error!
The above example shows a simple definition and how arguments are checked. Similarly the return types are checked when your function completes:
const fn = gen`
(string, number, number) => [string, number]
`((str, a, b) => null)
fn('test', 1, 2) // error!
The second function, type
is used to alias type signatures to a variable. It can be used to predefine
some types which can then be interpolated into your gen
definition.
import { gen, type } from 'runruntypes';
const Errorish = type`
{ message: ?string }
`;
const isError = gen`(${Errorish} | void) => bool`(err => {
return err !== undefined && !!err.message;
});
This extracts an object definition type outside of the gen
definition. For comparison, without a type alias
you'd simply write this definition inline, which can become tedious if it's being used and repeated quite often:
import { gen } from 'runruntypes';
const isError = gen`
({ message: ?string } | void) => bool
`(err => {
return err !== undefined && !!err.message;
});
RunRunTypes
uses the @babel/parser
to parse any input to it. A large subset of Flow type annotations
will be parsed without a problem and will be correctly check. You can always expect this library
to throw a TypeError
when it either:
Feel free to read more about Flow type annotations here
type
A tagged template literal that accepts a Flow type definition consisting of any of the supported types and syntax.
This will return a function that checks the first argument against the type definition and returns true
if it
passes the type checks and false
if it doesn't.
type`string`('test') // true
type`{ x: 1 }`({ x: 2 }) // false
gen
A tagged template literal that accepts a Flow arrow function type definition consisting of any of the supported types and syntax.
It expects any number of arguments and a return type. Normal type definitions that are not function definitions will cause it to throw an error.
It returns a factory function that wraps any function passed as the first argument in a new type checked and guarded function, i.e. it'll expect the argument to comply to the type definition that has been defined and will enforce it.
gen`string => string`(x => 'Hello, ' + x)('Luke')
gen`(number, 4) => string`((a, b) => '' + a + b)(2, 4)
Currently the following types are supported:
bool
, number
, string
, null
, void
, any
)true
, false
, 2
, "hello"
)?number
, i.e. null
, undefined
, number
)number[]
)[number, number]
){ x: number }
without support for optionals nor methods)number | string
meaning that both are allowed){ x: 1 } & { y: 2 }
meaning that both must match)Date
or Element
which will simply check the constructor's name)Object
to match any object, Function
to match any function)You can mix and combine the types as you'd expect in a real typed language.
Remember that gen
expects a function definition and type
any of the above.