TypeScript library for writing
fully typechecked + runtime validated functions
using Zod.
$ npm i @divs1210/zaphod
import z from 'zod'
import { Fn, check } from '@divs1210/zaphod'
// zod schema for integers
const zInt = z.number().int()
// zod schema for even numbers
const zEven = zInt.refine(
x => x % 2 === 0,
'should be even'
)
// zod schema for odd numbers
const zOdd = zInt.refine(
x => !check(zEven, x),
'should be odd'
)
// zaphod Fn incEven: (x: zEven) => zOdd
const incEven = Fn()
.args(zEven)
.returns(zOdd)
.implement(x => x + 1)
incEven
is now a fully statically typechecked + runtime validated function!
incEven(2) // => 3
incEven('2') // => TS error (string is not number)
incEven(1) // => validation error (1 is not even)
import { ValidationMode } from '@divs1210/zaphod'
const incEven = Fn()
.args(zEven)
.returns(zOdd)
// disable runtime validation
.setValidationMode(ValidationMode.None)
.implement(x => x + 1)
The default mode is Both
.
Others available are Args
, Ret
, and None
.
import { Schema } from '@divs1210/zaphod'
const map = <X extends Schema, Y extends Schema>(X: X, Y: Y, L: number) => Fn()
.args( // argslist: [
z.array(X).length(L), // X[] of length L
z.function().args(X).returns(Y) // (x: X) => Y
) // ]
.returns(z.array(Y).length(L)) // returns: Y[] of length L
.implement((xs, f) => xs.map(x => f(x)))
const xs = [1, 2, 3]
const ys = map(zInt, zInt, xs.length)(xs, x => x + 1)
The call to map
might look weird,
but it is roughly equivalent to the following pseudo-TS:
const ys = map<number, number, xs.length>(xs, x => x + 1)
If you squint, you might see dependent types in here...
Yes, Zod already provides a way to define function schemas and implement them:
const f = z
.function()
.args(z.number())
.returns(z.string())
.implement(x => '' + x)
but it ALWAYS validates the arguments schemas, and also the return schema (if provided).
Zaphod allows you to turn off validation for arguments, return values, or both - enabling you to write code in a style akin to dependent typing.
You can validate all functions during development, and disable validation for all but the edge functions (I/O) in production.