Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@rorystokes/ad-ts

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rorystokes/ad-ts

ADTs for TypeScript

  • 0.1.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

AD-Ts

build status npm downloads

Bringing Pattern Matching and other ADT and Functional Programming concepts to TypeScript. Borrows heavily from and builds on top of @gcanti's fp-ts library.

Submodules

match

The match submodule provides simple, type-safe 'pattern matching' across a TaggedUnion. This requires each instance of any of the types in the union to have an explicit _tag value to uniquely identify the type they belong to.

Many of the types provided by fp-ts including Option and Either already have such tags, and as such a TaggedUnion can be constructed using these types.

TaggedUnions must be used instead of native TypeScript Unions as they encode the mapping from tags to types in a form that the type system can leverage to provide safety in match methods.

caseclass

The caseclass submodule is designed to supplement the usage of match, providing an easy way to define a tagged type, including specifying default values.

patternmatch

The patternmatch submodule allows for more generic pattern matching across any values. It always returns a fp-ts Option, as exhaustivity testing is not possible.

Patterns can either be simple boolean guards, or extractor methods that return optional extracted results.

do

The do submodule aims to provide equivalent syntax to for comprehensions in Scala or do in Haskell (see Wikipedia's page on Monads)

This depends heavily on the Monad HKT defined by fp-ts.

Examples

Do syntax

import { doOn } from '@rorystokes/ad-ts/do';
import { Either, either, left, right } from 'fp-ts/lib/Either';

const numberOrError = (s: string): Either<string, number> => {
    const n = Number.parseFloat(s)
    return Number.isNaN(n) ? left(`'${s}' is not a number`) : right(n)
}

const sqrtOrError = (n: number): Either<string, number> => {
    const sqrt = Math.sqrt(n)
    return Number.isInteger(sqrt) ? right(sqrt) : left(`${n} is not a square number]`)
}

const testString = (s: string) => doOn(either)
    .with("s", s)
    .bind("n", ({s}) => numberOrError(s))
    .bind("sqrt", ({n}) => sqrtOrError(n))
    .yield(({sqrt}) => sqrt)

testString("9")       // right(3)
testString("8")       // left("8 is not a square number")
testString("seven")   // left("'seven' is not a number")

Matching on Classes

import { match, TaggedUnion, TypeTag } from '@rorystokes/ad-ts/match'

class Foo {
    readonly [TypeTag]: "Foo"
    constructor(readonly name: string) { }
}

class Bar {
    readonly [TypeTag]: "Bar"
    constructor(readonly fn: string, readonly sn: string) { }
}

type FooBar = TaggedUnion<{
    Foo: Foo,
    Bar: Bar
}>


const getName = (foobar: FooBar) => match(foobar)({
    Foo: ({ name }) => name,
    Bar: ({ fn, sn }) => `${fn} ${sn}`
})

getName(new Foo("Alan"))           // "Alan"
getName(new Bar("Bob", "Brown"))   // "Bob Brown"

Matching on Case Class

import { match, TaggedUnion } from '@rorystokes/ad-ts/match'
import { CaseClass, Default } from '@rorystokes/ad-ts/caseclass'


const Foo = CaseClass("Foo")<{
    name: string,
    size?: number
}>()
type Foo = ReturnType<typeof Foo>

const Bar = CaseClass("Bar")<{
    label: string,
    prefix: Default<string>
}>({
    prefix: "Bar:"
})
type Bar = ReturnType<typeof Bar>

type FooBar = TaggedUnion<{
    Foo: Foo,
    Bar: Bar
}>


const getName = (foobar: FooBar) => match(foobar)({
    Foo: ({ name }) => name,
    Bar: ({ label, prefix }) => `${prefix} ${label}`
})


getName(Foo({ name: "Alan" }))                 // "Alan"
getName(Bar({ label: "Bob" }))                 // "Bar: Bob"
getName(Bar({ label: "Carol", prefix: ">>" })) // ">> Carol"

Pattern matching

import { patternmatch, Pattern } from '@rorystokes/ad-ts/patternmatch'
import { none, some } from 'fp-ts/lib/Option';

const IsInteger: Pattern<number, number> = Number.isInteger

const Square: Pattern<number, { i: number, sqrt: number }> = (i: number) => {
    const sqrt = Math.sqrt(i)
    return Number.isInteger(sqrt) ? some({ i, sqrt }) : none
}

const checkNumber = patternmatch<number>({ Square, IsInteger })({
    Square: ({ sqrt, i }) => `${i} is ${sqrt}^2`,
    IsInteger: (i) => `${i} is an integer`
})

checkNumber(3)    // some("3 is an integer")
checkNumber(4)    // some("4 is 2^2")
checkNumber(5.6)  // none

With fp-ts

See https://github.com/gcanti/fp-ts

Options

import { match, TaggedUnion } from '@rorystokes/ad-ts/match'
import { Some, None, some, none } from 'fp-ts/lib/Option'

type TaggedOption<A> = TaggedUnion<{
    Some: Some<A>,
    None: None<A>
}>

const valueOrEmpty = (opt: TaggedOption<string>) => match(opt)({
    Some: ({value}) => value,
    None: () => "Empty"
})


valueOrEmpty(some("Full")) // "Full"
valueOrEmpty(none)         // "Empty"

Eithers

import { match, TaggedUnion } from '@rorystokes/ad-ts/match'
import { Left, Right, left, right } from 'fp-ts/lib/Either'

type TaggedEither<A,B> = TaggedUnion<{
    Left: Left<A, B>,
    Right: Right<A, B>
}>

const getString = (either: TaggedEither<number, string>) => match(either)({
    Left: ({value}) => `#${value}`,
    Right: ({value}) => `'${value}'`
})


getString(left(42))        // "#42"
getString(right("hello"))  // "'hello'"

FAQs

Package last updated on 21 Mar 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc