npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rorystokes/ad-ts

v0.1.0

Published

ADTs for TypeScript

Downloads

17

Readme

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'"