tagmeme v0.0.10
Tagmeme
Tagged unions
npm install tagmemeTagmeme is a library for building tagged unions. This project offers:
- A concise API for pattern matching and variant constructors
- Data-oriented tags that can be serialized and namespaced
- Errors in development to ensure exhaustive pattern matching
- Small size and zero-dependencies in production using dead code elimination
Let's check it out.
Examples
import assert from 'assert'
import { union } from 'tagmeme'
const Result = union(['Ok', 'Err'])
const err = Result.Err(new Error('My error'))
const message = Result.match(err, {
Ok: () => 'No error',
Err: error => error.message
})
assert(message === 'My error')
const handle = Result.matcher({
Ok: () => 'No error',
Err: error => error.message
})
assert(handle(err) === 'My error')
const isError = Result.matches(err, Result.Err)
assert(isError)Documentation
This package includes:
union(types, options)Union[type](data)Union.match(tag, handlers, catchAll)Union.matcher(handlers, catchAll)Union.matches(tag, variant)safeUnion(types, options)
union
union(types: Array<String>[, options: { prefix: String }]): Union
Create a tagged union. Throws if:
typesis not an array of unique strings- any
typesare named "match", "matcher", or "matches"
See safeUnion if using arbitrary strings.
Union[type]
Union[type](data: any): ({ type, data })
Create a tag of the union containing data which can be retrieved via Union.match.
import assert from 'assert'
import { union } from 'tagmeme'
const Result = union(['Ok', 'Err'])
const result = Result.Ok('good stuff')
assert(result.type === 'Ok')
assert(result.data === 'good stuff')Union.match
Union.match(tag, handlers[, catchAll: function])
Pattern match on tag with a hashmap of handlers where keys are kinds and values are functions, with an optional catchAll if no handler matches the value.
Throws if:
tagis not of any of the union typestagdoes not match any type and there is nocatchAll- any
handlerskey is not a kind in the union - any
handlersvalue is not a function - it handles all cases and there is a useless
catchAll - it does not handle all cases and there is no
catchAll
import assert from 'assert'
import { union } from 'tagmeme'
const Result = union(['Ok', 'Err'])
const result = Result.Err('Request failed')
const status = Result.match(
result,
{ Err: () => 400 },
() => 200
})
assert(status === 400)Union.matcher
Union.matcher(handlers[, catchAll: function])
Create a matching function which will take tag and context arguments.
This reduces the boilerplate of a function that delegates to Union.match with static handlers.
This is also a bit faster than match because the handler functions only need to be created once.
Unlike with match, the second argument to handlers will be context to avoid the need for a closure.
import assert from 'assert'
import { union } from 'tagmeme'
const Result = union(['Ok', 'Err'])
const collectErrors = Result.matcher({
Ok: (_, errors) => errors,
Err: (error, errors) => errors.concat(error)
})
const errors = collectErrors(Result.Err('Bad'), [])
assert.deepEqual(errors, ['Bad'])Union.matches
Union.matches(tag, variant: Variant): Boolean
Determine whether a given tag is of variant.
import assert from 'assert'
import { union } from 'tagmeme'
const Result = union(['Ok', 'Err'])
const okTag = Result.Ok(1)
assert(Result.matches(okTag, Result.Ok))safeUnion
safeUnion(types: Array<String>[, options: { prefix: String }]): { methods, variants }
For library authors accepting arbitrary strings for type names, safeUnion is union but returns distinct collections of methods and type variants.
This will not throw if a type is "match", "matcher", or "matches".
Name
tagmeme |ˈtaɡmiːm|: a slot in a syntactic frame which may be filled by any member of a set of appropriate linguistic items.
This name is kind of fitting for a tagged union library.