Say I have some async function which fetches from an api and returns a taskEither (for simplicity, I'm providing a basic async task either:
const someAsyncFunction = taskEither.fromPredicate(
(value: number) => value < 12,
(value: number) => new Error("value was greater than 12")
)
I then want to report the error to sentry if it exists, however, I wish to inject a default value and continue downstream execution
const reportError = (error: Error) => console.log(error.message)
type ExceptionHandler = typeof reportError
const unwrapAndReportError = <R>(captureFunction: ExceptionHandler) => (
def: R
) => (inputEither: taskEither.TaskEither<Error, R>): R =>
E.getOrElse((err: Error) => {
captureFunction(err)
return def
})(inputEither)
const runAsyncFunctionThenUnwrapAndReport = flow(
someAsyncFunction,
unwrapAndReportError(reportError)("potato")
)
This code fails to typecheck with:
Argument of type 'TaskEither<Error, R>' is not assignable to parameter of type 'Either<Error, R>'
Fully runnable example: https://codesandbox.io/s/fp-ts-playground-forked-dy2xyz?file=/src/index.ts:0-722
My question is, how can this effect be achieved using fp-ts? What is the recommended pattern here (and how can I get it to typecheck).
Looks like you're pretty close, getOrElse
should work, although I think you're importing that from the Either
module. Replace that with an import from the TaskEither
module. Also, it's more idiomatic to use pipe
so you can supply your task either argument first.
Perhaps something like this?
import * as TE from "fp-ts/lib/TaskEither"
import * as T from "fp-ts/lib/Task"
import { pipe } from "fp-ts/lib/function"
const someAsyncFunction = TE.fromPredicate(
(value: number) => value < 12,
(value: number) => new Error("value was greater than 12")
)
const reportError = (error: Error) => console.log(error.message)
type ExceptionHandler = typeof reportError
const unwrapAndReportError = <R>(captureFunction: ExceptionHandler) => (
def: R
) => (inputEither: TE.TaskEither<Error, R>): Promise<R> =>
pipe(
inputEither,
TE.getOrElse(
(error) => {
captureFunction(error)
return T.of(def)
},
),
)()
const runAsyncFunctionThenUnwrapAndReport = flow(
someAsyncFunction,
unwrapAndReportError(reportError)("potato")
)