- NAME
- FEATURES
- INSTALLATION
- SYNOPSIS
- DESCRIPTION
- EXPORTS
- DEVELOPMENT
- COMPATIBILITY
- SEE ALSO
- VERSION
- AUTHOR
- COPYRIGHT AND LICENSE
Box - put a value in a box
- no dependencies
- < 170 B minified + gzipped
- fully typed (TypeScript)
- CDN builds (UMD) - jsDelivr, unpkg
$ npm install @chocolatey/box
import $ from '@chocolatey/box'
$(42) // Box<42>
$(42).value() // 42
$(42).map(it => it + 1) // Box<43>
$(42).tap(console.log) // Box<42>
$(42).then(it => it + 1) // 43
$(42, it => it + 1) // 43
// "*.tar.gz" -> "*.gz"
const untar = name => $(name)
.map(it => it.split('.'))
.tap(it => it.splice(1, 1))
.then(it => it.join('.'))
untar('package.tar.gz') // "package.gz"
Box puts a value in a container which exposes a handful of methods to facilitate piping values through a series of functions.
It provides a lightweight implementation of the box pattern, which allows the right-to-left flow of function composition to be expressed via the left-to-right syntax of method chaining familiar from jQuery, Lodash, promises etc.
import R from 'ramda'
const fn1 = value => baz(bar(foo(value)))
const fn2 = R.compose(baz, bar, foo)
import $ from '@chocolatey/box'
const fn = value => $(value).map(foo).map(bar).then(baz)
Because:
composition and dot chaining are the same, and dot chaining is more ergonomic in JavaScript
โ Brian Lonsdorf
If you're using Babel, pipelines can be written natively with features such as the pipeline operator, do expressions and partial application, e.g.:
import { tap } from 'lodash'
const untar = name =>
name.split('.')
|> tap(#, it => it.splice(1, 1))
|> #.join('.')
If you're already using Lodash/Underscore or similar, you can use their built-in methods to implement pipelines, e.g.:
import _ from 'lodash'
const untar = name =>
_(name)
.split('.')
.tap(it => it.splice(1, 1))
.join('.')
- Type:
<T, R>(value: T, fn: (value: T) => R): R
<T>(value: T): Box<T>
- Aliases: $, box
import $ from '@chocolatey/box'
$(42) // Box<42>
$(42, it => it + 1) // 43
The default export is a function which either takes a value and puts it in a
box (via Box.of
) or takes a value and a function and applies the
function to the value.
The latter provides a convenient shorthand for passing an argument to an IIFE, e.g.:
const counter = (function () {
let count = 0
return () => ++count
})()
counter() // 1
counter() // 2
counter() // 3
const counter = (function (count) { return () => ++count })(0)
const counter = $(0, count => () => ++count)
- Type:
new <T>(value: T) => Box<T>
import { Box } from '@chocolatey/box'
const box = new Box(42) // Box<42>
Creates a new Box instance containing the supplied value.
- Type:
<T>(value: T) => Box<T>
import { Box } from '@chocolatey/box'
const box = Box.of(42) // Box<42>
const boxes = [1, 2, 3].map(Box.of) // [Box<1>, Box<2>, Box<3>]
Returns a new Box
instance containing the supplied value.
Note that of
is a function which returns a Box instance rather than a method
which returns an instance of its invocant, so the following are equivalent:
class MyBox extends Box {} // XXX missing `of` override
const array = [1, 2]
array.map(it => Box.of(it)) // [Box<1>, Box<2>]
array.map(it => MyBox.of(it)) // [Box<1>, Box<2>]
array.map(Box.of) // [Box<1>, Box<2>]
array.map(MyBox.of) // [Box<1>, Box<2>]
- Type:
<U>(fn: (value: T) => U): Box<U>
import $ from '@chocolatey/box'
$(42).map(it => it + 1) // Box<43>
Applies the supplied function to the value and returns a new box containing the result.
- Type:
(fn: (value: T) => void): this
import $ from '@chocolatey/box'
$(42).tap(console.log) // Box<42>
Applies the supplied function to the value and returns the original box (the invocant). Useful to insert side effects, logging etc. into a pipeline without changing the value.
- Type:
<U>(fn: (value: T) => U): U
import $ from '@chocolatey/box'
$(42).then(it => it + 1) // 43
Returns the result of applying the supplied function to the value.
- Type:
(fn?: (value: T) => void): T
import $ from '@chocolatey/box'
$(42).value() // 42
$(42).value(console.log) // 42
Returns the value. If an optional function is supplied, it is applied to the
value before the value is returned. This is similar to tap
, except
the value is returned rather than the box.
The following NPM scripts are available:
- build - compile the library for testing and save to the target directory
- build:doc - generate the README's TOC (table of contents)
- build:release - compile the library for release and save to the target directory
- clean - remove the target directory and its contents
- rebuild - clean the target directory and recompile the library
- repl - launch a node REPL with the library loaded
- test - recompile the library and run the test suite
- test:run - run the test suite
- typecheck - sanity check the library's type definitions
- Maintained Node.js versions and compatible browsers
- fcf - a functional alternative to control-flow statements such as
if
,switch
andwhile
- fp-ts - functional programming in TypeScript
- Brian Lonsdorf - Create linear data flow with container style types (Box)
- Brian Lonsdorf - Oh Composable World!
1.2.0
Copyright ยฉ 2021 by chocolateboy.
This is free software; you can redistribute it and/or modify it under the terms of the MIT license.