runtime type checking

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))

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

	setPlain(other) {
		this.x = other.x
		this.y = other.y
	}

	set(other) {
		type(Coords, other)
		this.x = other.x
		this.y = other.y
	}
}

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
let x = new Coords(1, 1)
x.set(origin)
ready
plain - type
let x = new Coords(1, 1)
x.setPlain(origin)
ready

Revisions

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