解包任务、处理错误并提供默认值

Unwrapping a task either, handling errors, and providing default value

提问人:Abraham P 提问时间:9/8/2023 更新时间:9/8/2023 访问量:77

问:

假设我有一些异步函数,它从 api 获取并返回一个 taskEither(为简单起见,我提供了一个基本的异步任务:

const someAsyncFunction = taskEither.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: taskEither.TaskEither<Error, R>): R =>
  E.getOrElse((err: Error) => {
    captureFunction(err)
    return def
  })(inputEither)

const runAsyncFunctionThenUnwrapAndReport = flow(
  someAsyncFunction,
  unwrapAndReportError(reportError)("potato")
)

此代码无法进行类型检查:

Argument of type 'TaskEither<Error, R>' is not assignable to parameter of type 'Either<Error, R>'

完全可运行的示例:https://codesandbox.io/s/fp-ts-playground-forked-dy2xyz?file=/src/index.ts:0-722

我的问题是,如何使用 fp-ts 实现这种效果?这里推荐的模式是什么(以及如何让它进行类型检查)。

TypeScript 错误处理 任务 FP-TS

评论


答:

1赞 Parker Tailor 9/8/2023 #1

看起来你已经很接近了,应该可以工作,尽管我认为你是从模块中导入的。将其替换为模块中的导入。此外,它使用起来更习惯,因此您可以先提供任一参数。getOrElseEitherTaskEitherpipe

也许是这样的事情?

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")
)

评论

0赞 Abraham P 9/8/2023
我使用折叠来解决这个问题,但这个解决方案实际上似乎更明智,以后可能会返工我的!
0赞 Abraham P 9/8/2023 #2

我最终得到了这个工作:

import { taskEither as TE, function as F, task as T } from 'fp-ts'

const unwrapEitherAndReport = <R>(captureFunction: ExceptionHandler) => (def: R) => (inputEither: TE.TaskEither<Error,R>): T.Task<R>=> F.pipe(
    inputEither,
    TE.fold(
        (err) => {
            captureFunction(err)
            return T.of(def)
        },
        T.of
    )
)

并使用以下命令运行它:

F.flow(
  someAsyncFunction,
  unwrapEitherAndReport(handler)('potato')
)