runtime type checking (v2)

Revision 2 of this benchmark created on


Setup

/**
 * Guard - simple runtime type-checking
 *
 * const add = (x, y) => number(number(x) + number(y))
 */

const string = value => {
  if (typeof value !== 'string') {
    throw new TypeError(`Value ${value} is not type String`)
  }
  return value
}

const number = value => {
  if (typeof value !== 'number') {
    throw new TypeError(`Value ${value} is not type Number`)
  }
  return value
}

const nullish = value => {
  if (value != null) {
    throw new TypeError(`Value ${value} is not nullish`)
  }
  return value
}

const bool = value => {
  if (typeof value !== 'boolean') {
    throw new TypeError(`Value ${value} is not type Bool`)
  }
  return value
}

const symbol = value => {
  if (typeof value !== 'symbol') {
    throw new TypeError(`Value ${value} is not type Symbol`)
  }
  return value
}

const bigint = value => {
  if (typeof value !== 'bigint') {
    throw new TypeError(`Value ${value} is not type BigInt`)
  }
  return value
}

/**
 * Assert value either passes guard or is nullish.
 * Usage: `maybe(number, value)`
 */
const maybe = (guard, value) => {
  if (value == null) {
    return null
  }
  return guard(value)
}

/**
 * Guard that value is exactly a given type.
 */
const type = (constructor, value) => {
  if (value.constructor !== constructor) {
    throw new TypeError(`Type ${value.constructor.name} is not type ${constructor.name}`)
  }
  return value
}

/**
 * Guard that value is an instance of type.
 */
const instance = (constructor, value) => {
  if (!(value instanceof constructor)) {
    throw new TypeError(`Type ${value.constructor.name} is not instance of ${constructor.name}`)
  }
  return value
}

/**
 * Transform an assertion (statement-style function)
 * into a guard (expression-style function)
 */
const guards = (assert, value) => value => {
  assert(value)
  return value
}

const addPlain = (a, b) => a + b

const add = (a, b) =>
	number(number(a) + number(b))

const title = (title, fallback) =>
	maybe(string, title) ?? fallback

class Coords {
	constructor(x, y) {
		this.x = x
		this.y = y
	}
}

const xPlain = coords => coords.x

const x = coords => {
	type(Coords, coords)
	return number(coords.x)
}

let origin = new Coords(0, 0)

Test runner

Ready to run.

Testing in
TestOps/sec
typechecked
add(1, 1)
ready
plain
addPlain(1, 1)
ready
typechecked - type
x(origin)
ready
plain - type
xPlain(origin)
ready
maybe
title("Some title", "Untitled")
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.