|
1 | 1 | # MaybeTyped
|
2 | 2 |
|
3 | 3 | [](https://travis-ci.org/andnp/MaybeTyped)
|
4 |
| -[](https://greenkeeper.io/) |
5 | 4 | [](https://codecov.io/gh/andnp/MaybeTyped)
|
6 | 5 | [](https://github.com/semantic-release/semantic-release)
|
7 | 6 | [](https://snyk.io/test/github/andnp/maybetyped?targetFile=package.json)
|
| 7 | +[](https://greenkeeper.io/) |
8 | 8 |
|
9 | 9 | MaybeTyped is a well-typed Maybe (optional) monad written in typescript.
|
10 | 10 |
|
@@ -156,3 +156,87 @@ const nullable = maybe(value).asNullable();
|
156 | 156 |
|
157 | 157 | assert(nullable === value);
|
158 | 158 | ```
|
| 159 | + |
| 160 | +## MaybeT |
| 161 | +```typescript |
| 162 | +export function apiUserSearch(user: string): MaybeT<Promise<UserData>> { |
| 163 | + // if user does not exist, api returns undefined |
| 164 | + return maybeT(fetch(`some/uri?user=${user}`).json()); |
| 165 | +} |
| 166 | + |
| 167 | +const userBirthday = await apiUserSearch('yagami') |
| 168 | + .map(user => user.birthday) |
| 169 | + .map(date => new Date(date)) |
| 170 | + .orElse(() => Date.now()); // <- this is probably a bad design choice :P |
| 171 | + |
| 172 | +const userBirthdayPromises = maybeT(['misa misa', 'light', null, 'ryuk']) |
| 173 | + .map(apiUserSearch) |
| 174 | + .map(maybeUser => |
| 175 | + maybeUser |
| 176 | + .map(user => user.birthday) |
| 177 | + .map(date => new Date(date)) |
| 178 | + .orElse(() => Date.now())) |
| 179 | + .asNullable(); |
| 180 | + |
| 181 | +const userBirthdays = await Promise.all(userBirthdayPromises); |
| 182 | +``` |
| 183 | + |
| 184 | +## Api |
| 185 | + |
| 186 | +### maybeT |
| 187 | +`maybeT` is the constructor for a maybe transform. |
| 188 | +Anything with a `map` function can be transformed into a `maybeT`. |
| 189 | +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. |
| 190 | +```typescript |
| 191 | +const maybeThings = maybeT([1, 2, null, 4, undefined, 6]); // MaybeT<Array<number>> |
| 192 | +const maybeLater = maybeT(Promise.resolve('hey')); // MaybeT<Promise<string>> |
| 193 | +``` |
| 194 | + |
| 195 | +### map |
| 196 | +```typescript |
| 197 | +const things = maybeT(['1', '2', null, '4']) // MaybeT<Array<string>> |
| 198 | + .map(x => parseInt(x)); // MaybeT<Array<number>> |
| 199 | +``` |
| 200 | + |
| 201 | +### caseOf |
| 202 | +```typescript |
| 203 | +const things = maybeT([1, 2, null, 4]) |
| 204 | + .caseOf({ |
| 205 | + none: () => 4, |
| 206 | + some: x => x + 1, |
| 207 | + }); // MaybeT<Array<number>> => MaybeT<[2, 3, 4, 5]> |
| 208 | +``` |
| 209 | + |
| 210 | +### orElse |
| 211 | +```typescript |
| 212 | +const things = maybeT([1, 2, null, 4]) |
| 213 | + .orElse(3); // MaybeT<Array<number>> => MaybeT<[1, 2, 3, 4]> |
| 214 | +``` |
| 215 | + |
| 216 | +### asNullable |
| 217 | +```typescript |
| 218 | +const things = maybeT([1, 2, null, 4]) |
| 219 | + .asNullable(); // Array<number> => [1, 2, null, 4] |
| 220 | +``` |
| 221 | + |
| 222 | +### asType |
| 223 | +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). |
| 224 | +This means that after most operations the type will become `MaybeT<MonadLike<*>>`. |
| 225 | +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. |
| 226 | +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. |
| 227 | +This method also asks for the contained type, but because we _haven't_ forgotten that, we will be able to check that. |
| 228 | + |
| 229 | +Programmatic examples below should help make this more clear. |
| 230 | +```typescript |
| 231 | +const a = maybeT(Promise.resolve('hi')) |
| 232 | + .asType<Promise<string>>(Promise); // Promise<string> => this is correct |
| 233 | + |
| 234 | +const b = maybeT(Promise.resolve('hey')) |
| 235 | + .asType<Array<string>>(Array); // Array<string> => this will throw a runtime err, but not a compile err |
| 236 | + |
| 237 | +const c = maybeT(Promise.resolve('hello')) |
| 238 | + .asType<Promise<number>>(Promise); // any => this will throw a compile err, but not runtime |
| 239 | + |
| 240 | +const d = maybeT(Promise.resolve('merp')) |
| 241 | + .asType<Promise<string>>(Array); // any => this will throw a compile err and runtime |
| 242 | +``` |
0 commit comments