Contracts

Benchmark created on


Description

Racket-style contracts in JS

Setup

const val = (assert, value) => {
  assert(value)
  return value
}

const asserting = predicate => value => {
  if (!predicate(value)) {
    throw new TypeError(`Expected ${predicate.name} but got ${value}`)
  }
}

const isString = value => typeof value === 'string'
const string = asserting(isString)

const isNumber = value => typeof value === 'number'
const number = asserting(isNumber)

const isBool = value => typeof value === 'bool'
const bool = asserting(isBool)

const isSymbol = value => typeof value === 'symbol'
const symbol = asserting(isSymbol)

const isBigInt = value => typeof value === 'bigint'
const bigint = asserting(isBigInt)

const isFunc = value => typeof value === 'function'
const func = asserting(isFunc)

const isNone = value => value == null

/**
 * Assert that value is exactly a given type.
 */
const isType = constructor => value => value.constructor === constructor 
const type = constructor => asserting(isType(constructor))

/**
 * Assert that value is an instance of type.
 */
const isInstance = constructor => value => value instanceof constructor
const instance = constructor => asserting(isInstance(constructor))

const array = asserting(Array.isArray)

/**
 * Create a maybe type for an assertion.
 * Passes if value is nullish or passes assertion.
 */
const maybe = assert => value => {
  if (isNone(value)) {
    return value
  }
  assert(value)
  return value
}

/**
 * Decorate a function with a contract
 */
const contract = (
  signature,
  returns,
  func
) => (...args) => {
  for (var i = 0; i < signature.length; i++) {
    let assert = signature[i]
    assert(args[i])
  }
  return returns(func(...args))
}

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

const addAssert = (a, b) => {
	number(a)
	number(b)
	return val(number, a + b)
}

const addContract = contract(
  [number, number],
  number,
  addPlain
)

Test runner

Ready to run.

Testing in
TestOps/sec
add - contract
addContract(1, 1)
ready
addPlain - no contract
addPlain(1, 1)
ready
addAssert
addAssert(1, 1)
ready

Revisions

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