From ff150e0b950097a83c38d52904f8a822a386870d Mon Sep 17 00:00:00 2001 From: "andy.patterson" Date: Mon, 30 Apr 2018 09:41:47 -0400 Subject: [PATCH] docs: add maybeT to documentation --- README.md | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f92c27e..13ba70d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # MaybeTyped [![Build Status](https://travis-ci.org/andnp/MaybeTyped.svg?branch=master)](https://travis-ci.org/andnp/MaybeTyped) -[![Greenkeeper badge](https://badges.greenkeeper.io/andnp/MaybeTyped.svg)](https://greenkeeper.io/) [![codecov](https://codecov.io/gh/andnp/MaybeTyped/branch/master/graph/badge.svg)](https://codecov.io/gh/andnp/MaybeTyped) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![Known Vulnerabilities](https://snyk.io/test/github/andnp/maybetyped/badge.svg?targetFile=package.json)](https://snyk.io/test/github/andnp/maybetyped?targetFile=package.json) +[![Greenkeeper badge](https://badges.greenkeeper.io/andnp/MaybeTyped.svg)](https://greenkeeper.io/) MaybeTyped is a well-typed Maybe (optional) monad written in typescript. @@ -156,3 +156,87 @@ const nullable = maybe(value).asNullable(); assert(nullable === value); ``` + +## MaybeT +```typescript +export function apiUserSearch(user: string): MaybeT> { + // if user does not exist, api returns undefined + return maybeT(fetch(`some/uri?user=${user}`).json()); +} + +const userBirthday = await apiUserSearch('yagami') + .map(user => user.birthday) + .map(date => new Date(date)) + .orElse(() => Date.now()); // <- this is probably a bad design choice :P + +const userBirthdayPromises = maybeT(['misa misa', 'light', null, 'ryuk']) + .map(apiUserSearch) + .map(maybeUser => + maybeUser + .map(user => user.birthday) + .map(date => new Date(date)) + .orElse(() => Date.now())) + .asNullable(); + +const userBirthdays = await Promise.all(userBirthdayPromises); +``` + +## Api + +### maybeT +`maybeT` is the constructor for a maybe transform. +Anything with a `map` function can be transformed into a `maybeT`. +Due to the commonality of the use case, support for `thenables` is also added, though be warned that `then` matches `flatMap` semantics, not `map` semantics. +```typescript +const maybeThings = maybeT([1, 2, null, 4, undefined, 6]); // MaybeT> +const maybeLater = maybeT(Promise.resolve('hey')); // MaybeT> +``` + +### map +```typescript +const things = maybeT(['1', '2', null, '4']) // MaybeT> + .map(x => parseInt(x)); // MaybeT> +``` + +### caseOf +```typescript +const things = maybeT([1, 2, null, 4]) + .caseOf({ + none: () => 4, + some: x => x + 1, + }); // MaybeT> => MaybeT<[2, 3, 4, 5]> +``` + +### orElse +```typescript +const things = maybeT([1, 2, null, 4]) + .orElse(3); // MaybeT> => MaybeT<[1, 2, 3, 4]> +``` + +### asNullable +```typescript +const things = maybeT([1, 2, null, 4]) + .asNullable(); // Array => [1, 2, null, 4] +``` + +### asType +Because typescript does not have support for higher-kinded-types (HKT), we lose track of which monad-like HKT we are dealing with (`Array` or `Promise` or other). +This means that after most operations the type will become `MaybeT>`. +To cope with this, we provide an `asType` method that will allow us to properly "remember" what type of monad we were originally dealing with. +A little type safety will be lost here, as you could lie and say this is an `Array` instead of a `Promise`, but the constructor that is passed in to this method will confirm the type at runtime. +This method also asks for the contained type, but because we _haven't_ forgotten that, we will be able to check that. + +Programmatic examples below should help make this more clear. +```typescript +const a = maybeT(Promise.resolve('hi')) + .asType>(Promise); // Promise => this is correct + +const b = maybeT(Promise.resolve('hey')) + .asType>(Array); // Array => this will throw a runtime err, but not a compile err + +const c = maybeT(Promise.resolve('hello')) + .asType>(Promise); // any => this will throw a compile err, but not runtime + +const d = maybeT(Promise.resolve('merp')) + .asType>(Array); // any => this will throw a compile err and runtime +```