Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/joanllenas/ts.data.maybe

A Typescript implementation of the Maybe data type
https://github.com/joanllenas/ts.data.maybe

just maybe nothing option typescript

Last synced: 15 days ago
JSON representation

A Typescript implementation of the Maybe data type

Awesome Lists containing this project

README

        

# Maybe

[![Build Status](https://travis-ci.org/joanllenas/ts.data.maybe.svg?branch=master)](https://travis-ci.org/joanllenas/ts.data.maybe)
[![npm version](https://badge.fury.io/js/ts.data.maybe.svg)](https://badge.fury.io/js/ts.data.maybe)

Maybe encapsulates the idea of a value that might not be there.

A Maybe value can either be `Just` some value or `Nothing`.

```ts
type Maybe = Just | Nothing;
```

Where `Nothing` is an instance of `Nothing`, `null` or `undefined`, and `Just` represents any non `Nothing` value.

> If this is new to you, you may want to read the introductory article [Safer code with container types](https://blog.logrocket.com/safer-code-with-container-types-either-and-maybe/) about why and how to use this library.

## Install

```
npm install ts.data.maybe --save
```

## Example 1

```ts
import { Maybe, just, withDefault, map2 } from 'ts.data.maybe';

interface User {
email: string;
name: Maybe;
surname: Maybe;
}
const user: User = {
email: '[email protected]',
name: just('John'),
surname: just('Doe')
};

const getFullName = (name: string, surname: string) => `${name} ${surname}`;
const maybeFullname = map2(getFullName, user.name, user.surname); // Just('John Doe')
console.log(withDefault(maybeFullname, '')); // 'John Doe'
```

## Example 2

```ts
const prices: Maybe[] = [
just(300),
nothing(),
just(500),
just(150),
nothing()
];
const sum = (a: number, b: number) => a + b;
const total = prices
.filter(n => !equals(n, nothing()))
.reduce((acc, current) => map2(sum, acc, current), just(0));
console.log(withDefault(total, 0)); // 950
```

## Api

_(Inspired by elm-lang)_

### just

`just(value: T): Maybe;`

Wraps a value in an instance of `Just`.

```ts
just(5); // Just(5) (Maybe)
```

### nothing

`nothing(): Maybe;`

Creates an instance of `Nothing`.

```ts
nothing(); // Nothing (Maybe)
```

> It's recommended to parametrize the function, otherwise the resolved type will be `Maybe` and type won't flow through `map`, `andThen` and so on.

### isJust

`isJust(value: Maybe): value is Just;`

Returns true if a value is an instance of `Just`.

```ts
isJust(nothing()); // false
```

### isNothing

`isNothing(value: Maybe): value is Nothing;`

Returns true if a value is an instance of `Nothing`.

```ts
isNothing(just(5)); // false
isNothing(undefined); // true
isNothing(null); // true
isNothing(nothing()); // true
```

### withDefault

`withDefault(value: Maybe, defaultValue: A): A;`

If `value` is an instance of `Just` it returns its wrapped value, if it's an instance of `Nothing` it returns the `defaultValue`.

```ts
withDefault(just(5), 0); // 5
withDefault(nothing(), 'hola'); // 'hola'
```

### caseOf

`caseOf(caseof: {Just: (v: A) => B; Nothing: () => B;}, value: Maybe): B;`

Run different computations depending on whether a `Maybe` is `Just` or `Nothing` and returns the result.

```ts
caseOf(
{
Nothing: () => 'Do nothing',
Just: n => `Launch ${n} missiles`
},
just(5)
); // 'Launch 5 missiles'
```

### map

`map(f: (a: A) => B, value: Maybe): Maybe;`

Transforms a `Maybe` value with a given function.

```ts
const add1 = (n: number) => n + 1;
map(add1, just(4)); // Just(5)
map(add1, nothing()); // Nothing
```

There are `map2`, `map3`, `map4`, `map5` and `mapN` functions too:

```ts
map2
(
f: (a: A, b: B) => C,
a: Maybe
, b: Maybe
): Maybe
```

An example with `map2`:

```ts
const safeParseInt = (num: string): Maybe => {
const n = parseInt(num, 10);
return isNaN(n) ? nothing() : just(n);
};
const sum = (x: number, y: number) => x + y;
const safeStringSum = (x: string, y: string) =>
map2(sum, safeParseInt(x), safeParseInt(y));
safeStringSum('1', '2'); // Just(3)
safeStringSum('a', '2'); // Nothing
```

If you need to parametrize the function with more than one argument, use the `map` that matches your parametrization.

> `mapN` only accepts arguments of the same type)

```ts
map3
(
f: (a: A, b: B, c: C) => D,
a: Maybe
, b: Maybe, c: Maybe
): Maybe
```

```ts
map4
(
f: (a: A, b: B, c: C, d: D) => E,
a: Maybe
, b: Maybe, c: Maybe, d: Maybe
): Maybe
```

```ts
map5
(
f: (a: A, b: B, c: C, d: D, e: E) => F,
a: Maybe
, b: Maybe, c: Maybe, d: Maybe, e: Maybe
): Maybe
```

```ts
mapN
(
f: (...a: A[]) => B,
...a: Maybe
[]
): Maybe
```

### andThen

`andThen(f: (a: A) => Maybe, v: Maybe): Maybe;`

Chains together many computations that may fail.

```ts
const head = (arr: string[]) => (arr.length > 0 ? just(arr[0]) : nothing());
andThen(head, just(['a', 'b', 'c'])); // Just('a')
andThen(head, just([])); // Nothing
```

### equals

`equals(a: Maybe, b: Maybe): boolean;`

Compares two `Maybe` instances and returns `true` when both are `Nothing` or their wrapped values are strictly equal (===), `false` otherwise.

```ts
equals(just(5), just(5); // true
equals(just(6), just(5); // false
equals(nothing(), just(5); // false
equals(nothing(), nothing(); // true
equals(null, nothing(); // true
equals(undefined, nothing(); // true
```