Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hojberg/seidr

A collection of general purpose Sum Types and Monads built on top of hojberg/sums-up
https://github.com/hojberg/seidr

Last synced: 2 months ago
JSON representation

A collection of general purpose Sum Types and Monads built on top of hojberg/sums-up

Awesome Lists containing this project

README

        

# Seidr

> In Old Norse, seiðr was a type of sorcery practiced in Norse society during
> the Late Scandinavian Iron Age. The practice of seiðr is believed to be a form
> of magic relating to both the telling and shaping of the future.

A collection of general purpose Sum Types and monads built on top of [hojberg/sums-up](https://github.com/hojberg/sums-up)

## Maybe

```ts
import { Just, Nothing } from 'seidr';

Just("Loki").caseOf({
Nothing: () => "N/A",
Just: name => `Hello ${name}`,
}); // => "Hello Loki"

Nothing().caseOf({
Nothing: () => "N/A",
Just: name => `Hello ${name}`,
}); // => "N/A"

// Map doesn't run on Nothing
Just("Loki").map(name => name.toUpperCase()); // => Just("LOKI")
Nothing().map(name => name.toUpperCase()); // => Nothing()

// flatMap unnests a layer when the mapper returns a Maybe
Just("Loki").flatMap(name => Just(name.toUpperCase())); // => Just("LOKI")
Nothing().flatMap(name => Just(name.toUpperCase())); // => Nothing()
```

## Result

```ts
import { Ok, Err } from 'seidr';

Ok("Loki").caseOf({
Err: err => err,
Ok: name => `Hello ${name}`,
}); // => "Hello Loki"

Err("oops").caseOf({
Err: err => err
Just: (name) => `Hello ${name}`,
}); // => "oops"

// Map doesn't run on Err
Ok("Loki").map(name => name.toUpperCase()); // => Just("LOKI")
Err("oops").map(name => name.toUpperCase()); // => Err("oops")

// flatMap unnests a layer when the mapper returns a Result
Ok("Loki").flatMap(name => Ok(name.toUpperCase())); // => Ok("LOKI")
Err("oops").flatMap(name => Ok(name.toUpperCase())); // => Err("oops")

// Result and Maybe are not isomorphic as "oops" is lost when converting Err to Nothing
Ok("Loki").toMaybe(); // => Just("Loki")
Err("oops").toMaybe(); // => Nothing()
```

## AsyncResult

An `AsyncResult` is a hybrid of a `Result` and a `Promise`,
with the type safety and convenience methods of the former, but the ability
to capture a not-necessarily-evaluated-yet value of the latter.

An `AsyncResult` can be constructed from a `Promise` with an
appropriate function to convert the promise's `unknown` error value to an `L`.

There are also `AsyncOk` and `AsyncErr` functions available as shorthand,
though in practice these are less frequently useful.

```ts
import { AsyncResult, AsyncOk, AsyncErr } from 'seidr';

////////////////////////////////////
// Constructing an AsyncResult

const myPromise: Promise<{ name: string }> = /* ... */;

AsyncResult.fromPromise(err => new Error(String(err)), myPromise);
// => AsyncResult

////////////////////////////////////
// Using an AsyncResult

// `caseOf` always returns a promise
AsyncOk("Loki").caseOf({
Err: err => err,
Ok: name => `Hello ${name}`,
}); // => Promise { : "Hello Loki" }

AsyncErr("oops").caseOf({
Err: err => err,
Ok: (name) => `Hello ${name}`,
}); // => Promise { : "oops" }

// `map` doesn't run on Err
AsyncOk("Loki").map(name => name.toUpperCase()); // => AsyncOk("LOKI")
AsyncErr("oops").map(name => name.toUpperCase()); // => AsyncErr("oops")

// `flatMap` unnests a layer when the mapper returns a Result, AsyncResult or Promise
AsyncOk("Loki").flatMap(name => Ok(name.toUpperCase())); // => AsyncOk("LOKI")
AsyncOk("Loki").flatMap(name => AsyncOk(name.toUpperCase())); // => AsyncOk("LOKI")
AsyncOk("Loki").flatMap(async name => Ok(name.toUpperCase())); // => AsyncOk("LOKI")
AsyncErr("oops").flatMap(name => Ok(name.toUpperCase())); // => AsyncErr("oops")

// `toPromise` returns promise that resolves on Ok or rejects on Err
// A `Promise` and an `AsyncResult` are isomorphic at runtime,
// as the error value isn't lost; only the type information is.
AsyncOk("Loki").toPromise(); // Promise { : "Loki" }
AsyncErr("oops").toPromise(); // Promise { : "oops" }
```

## Effect

```ts
import { Effect } from 'seidr';

const fooEff = Effect(() => "foo") // Effect("foo")

fooEff.unsafePerform() // => 'foo'

// Map doesn't run on Err
fooEff.map(val => val.toUpperCase()); // => Effect("FOO")

// flatMap unnests a layer when the mapper returns an Effect
fooEffect.flatMap(val => Effect(() => val + 'bar'); // => Effect("foobar")
```

## RemoteData

A sums-up implementation of the original pattern described by Kris Jenkins:
http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html

This is a helpful sum type for modelling data being fetched from the network.

```typescript
type RemoteData = NotAsked | Loading | Failure | Success
```

```typescript
import { RemoteData, NotAsked, Loading, Failure, Success } from 'seidr';

NotAsked().caseOf({
NotAsked: () => "not asked",
_: () => "everything else",
}); // => "not asked"

Loading().caseOf({
Loading: () => "loading",
_: () => "everything else",
}); // => "loading"

Failure("oops").caseOf({
Failure: err => err
_: () => "everything else",
}); // => "oops"

Success("Yay").caseOf({
Success: data => data
_: () => "everything else",
}); // => "yay"

// Map only runs on Success
Succecss("Loki").map(name => name.toUpperCase()); // => Just("LOKI")
Failure("oops").map(name => name.toUpperCase()); // => Failure("oops")
Loading().map(name => name.toUpperCase()); // => Loading()
NotAsked().map(name => name.toUpperCase()); // => NotAsked()

// flatMap unnests a layer when the mapper returns a Result when run on Success
Succecss("Loki").map(name => Success(name.toUpperCase())); // => Just("LOKI")
Failure("oops").map(name => Success(name.toUpperCase())); // => Failure("oops")
Loading().map(name => Success(name.toUpperCase())); // => Loading()
NotAsked().map(name => Success(name.toUpperCase())); // => NotAsked()
```