Skip to content

jmagaram/rescript-extras

Repository files navigation

ReScript Extras

Utilities for ReScript. Includes:

  • Sequences are now in a separate repository.
  • A lazy-promise Task and TaskResult
  • Untagged Union and Literal to construct and pattern match on discriminated unions of any kind
  • Useful extensions to Option, Result, and Array
  • NonEmptyArray for arrays with at least 1 item
  • A simple Test runner
  • Comparison utilities
  • Trampoline module to remove recursion

To install and use

npm install @jmagaram/rescript-extras

Add to your rescript.json...

{
  ...
+ "bs-dependencies": ["@jmagaram/rescript-extras"]
}

Everything is accessible in the root-level Extras module.

let arr = "abc" -> Extras.NonEmptyArray.of1
let opt = Some(1) -> Extras.Option.isSomeAnd(i => i >= 1)

Task and TaskResult

Inspired by TaskEither in fp-ts, a Task is a lazy promise that never fails. The Task.Result works with lazy promises that always return an Error or an Ok. Just like a regular result, you can transform it before execution with map, mapError, flatMap, and toOption. When ready to execute, call toPromise.

Union

The Union module provides functors to create tagged and untagged discriminated unions of 2, 3, 4, or 5 items. This is useful for interop with JavaScript libraries that produce or expect simple types like string | number and more complex types where the choices are tagged differently than how ReScript does it. See usage examples. Capabilities:

  • Discriminate (pattern match) on any programmable criteria, like typeof, instance of, lightweight shape detection (such as a tag), or parsing with a JSON parsing library.
  • All types can participate in a union.
  • Custom equality
  • Literal values like Null, Undefined, True, False, -1, and custom literals via MakeString, MakeInt, etc.
  • Built-in support for Int, String, Bool, Float, option<t>, nullable<t>, null<t>, and tuples of length 2 and 3

This implementation does not utilize any special compiler support and so there are some limitations:

  • Pattern matching must rely on a match function, not the usual matching syntax. Each case is distinguished by A | B | C | D. This can be easily improved by extending or wrapping the produced module; see the test file for examples.
  • Literal support and functors are a bit cumbersome
  • No genType support
  • No recursive type definition

Note: It is possible to create untagged unions with a library like rescript-struct and not use the functors defined in this package. See the usage examples for a comparision of the two approaches. This works very well and avoids abstractions, but requires a bit more code.

Note: The Rescript compiler has a new feature for untagged unions that works great with pattern matching support. There are limitations on which types can be included in the union, literal support is very nice, pattern matching is not customizable, and custom equality is not provided.

Literal

Functors to create Literal types of various kinds using MakeString and MakeInt and others. Includes built-in literals for True, False, and Null. You can create literals from reference types, and provide a custom equality operator to do things like case-insensitive string comparison. This implementation is completely type safe because each literal is its own unique type; you can't just cast any string to a "yes" for example.

Option

Existential quanitifiers isSomeAnd and isNoneOr. Create an option from a function that may fail using fromTryCatch. Combine options with concat, map2, map3, and map4. "Add" an option to a regular value using fold and foldBack. Includes lazy forms such as orElseWith.

NonEmptyArray

An array that must have at least one item in it. Include many of the usual functions like reduce, maxBy, minBy, map, mapi, concat, head, etc. Convert toArray and fromArray.

Array

Generate an array from a generator function using unfold. Various utilities like head, last, lastIndex, isEmpty, and prepend.

Result

Convert an array of results to a single result using fromArray and fromArrayMap. Create a result from a function that may fail with fromTryCatch. Transform an error with mapError.

Unknown

Similar to the Types module, includes functions to safely inspect unknown values like toString and toInt that returns an option. Can inspect properties on objects as well. Not intended for full-featured JSON parsing.

Cmp and CmpUtilities

Cmp.t is the ('a,'a) => float comparison function. The Cmp module provides comparison utilities such as as eq, neq, lt, gte, min, and max. fromMap makes it easy to generate a comparison function for an object based on a specific property in it. Or use reverse to change direction.

Functors MakeCompare and MakeEquals add sorting and equality functions to your custom data types.

Trampoline

Simple tools to remove recursion and avoid stack overflows.

Test runner

Super-simple test runner. Make tests using make and makeAsync. Run them using runSuite.