MaybeAsync is a wrapper (and hopefully a drop-in replacement) of
Promise<Maybe<T>>that allows you to process asynchronous values while also having error handling via Maybe. MaybeAsync even implements
PromiseLike, so you can await it just like a regular Promise.
That said, there are 2 ways of composing MaybeAsync values, just like there are two ways of working with Promises - async/await and chaining together transformations. If you squint hard you can see that MaybeAsync tries really hard to be a
monad transformer, which is true, but constraining it to Promises brought a tremendous amount of value and the trade-off is worth it.
import { MaybeAsync } from 'purify-ts/MaybeAsync'
function validateRequest(req: Request): Maybe<DeleteUserRequest>
function getUser(userId: number): Promise<Maybe<User>>
function deleteUserDb(user: User): Promise<Id<User>>
const deleteUser = (req): MaybeAsync<Id<User>> =>
MaybeAsync(async ({ liftMaybe, fromPromise }) => {
// when you have Maybe<T> and you want to get T out
const request = await liftMaybe(validateRequest(req))
// when you have Promise<Maybe<T>> and you want to get T out
const user = await fromPromise(getUser(request.userId))
return deleteUserDb(user)
})
const promise: Promise<Maybe<Id<User>>> = deleteUser(req).run()
const deleteUser = (req): MaybeAsync<Id<User>> =>
MaybeAsync.liftMaybe(validateRequest(req))
// Promise<Maybe<T>> or MaybeAsync<T> (both work)
// and you want to chain it
.chain(request => getUser(request.userId))
// when you have Promise<T> and you want to chain it
.chain(user => MaybeAsync(() => deleteUserDb(user)))
const promise: Promise<Maybe<Id<User>>> = deleteUser(req).run()