typescript - 如何将 Either 与异步函数一起使用

标签 typescript either fp-ts

我现在正在学习 fp-ts 并尝试用它的方法替换我的 API 的某些部分。

简单的例子:

  • 通过请求获取itemId
  • 将此 itemId 与异步函数一起使用来获取(或不获取)该项目

我发现的唯一方法是:

 const itemId: E.Either<string, Item["id"]> = pipe(
    body.itemId,
    E.fromNullable('Item ID is missed')
 );
 
 const item: E.Either<string, Item> = E.isLeft(itemId)
    ? itemId
    : pipe(
      await getItem(itemId.right),
      E.fromNullable('cant find item')
    );

它有效。但这是正确的方法吗?有没有办法在一个 pipe 函数中完成这一切? 谢谢。

最佳答案

这个问题有几个层次,因此我将提出一个可能的解决方案并逐步介绍它的工作原理。

首先,fp-ts 使用 Task s 来表示异步工作,因此大多数时候在 fp-ts 中使用异步代码时,您首先将代码转换为 TaskTaskEither (稍后会详细介绍)。首先,我们需要一个函数来执行 getItem 任务,并在返回 null 时返回 Either 而不是 null。这可以定义为:

import * as TE from 'fp-ts/lib/TaskEither';
import * as T from 'fp-ts/lib/Task';
// flow is function composition and avoids some syntax.
// This can be thought of a "point-free" although internally I use a
// not point-free function.
const getItemTE: (id: number) => TE.TaskEither<string, Item> = flow(
  getItem,
  // A task must be a function with no arguments that returns a promise,
  // This takes the result of calling getItem and returns a function that
  // returns that response in order to match the Task interface
  (promisedItem) => () => promisedItem,
  // We convert that task into a `TaskEither`, to get the type we want,
  // but note that this value will never be `left` because the underlying
  // task was returning `Item | null`. Both of those values are considered
  // a Right.
  TE.fromTask,
  // Converting to a TaskEither allows us to chain, which will hand us the
  // unwrapped `right` value and expects us to return a new TaskEither.
  // In this case, we want the task either we get by converting null
  // values into Eithers using the `fromNullable` function.
  TE.chain(TE.fromNullable("can't find item")),
);

现在我们有一个函数,它接受一个数字并生成一个 TaskEither 来获取该项目。

接下来,您希望将此函数与您的 body 对象一起使用。您可以将新创建​​的函数与 body 一起使用来获取项目:

// Note: at this point the Promise will be created so
// any IO is going to be kicked off here, not when the value
// is eventually awaited.
const item: TE.TaskEither<string, Item> = pipe(
  body.itemId,
  // This will wrap up the value into a task either
  // which enables us to chain.
  TE.fromNullable('Item id is missed'),
  // Now we just chain with the newly created function.
  // If the value is `right` then the value is fetched,
  // otherwise the 'Item id is missed' value is stored
  // in left and is returned.
  TE.chain(getItemTE)
);

最后,您可以使用该值执行以下操作:

async function doSomethingWithItem(item: TE.TaskEither<string, Item>) {
  pipe(
    // The item will already have been fetched at this point due
    // to the way the code is written. If you want to avoid fetching
    // the object right away, you might need to change around
    // the line where I went from the `getItem` response to a Task
    await item(),
    E.fold(
      (err) => console.error(err),
      (item) => {
        console.log(`Got item with id: ${item.itemId}`);
      },
    )
  );
}

doSomethingWithItem(item);

关于typescript - 如何将 Either 与异步函数一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75327019/

相关文章:

list - 从 Haskell 列表中获取第一个权限

error-handling - EitherT 是如何工作的?

typescript - 如何避免 fp-ts 中的嵌套 Monad 或优雅地处理它们?

javascript - 将 fp-ts TaskEither 与右侧的 Either 链接起来

typescript - fp-ts 和 Jest : ergonomic tests for Option and Either?

javascript - 返回类构造函数的函数的类型声明

javascript - JS : Convert Array of Strings to Array of Objects

javascript - 在 typescript 类型定义中表示内部类

javascript - 如何在 javascript/typescript 中 promise 一个具有多个动态变量的映射函数

scala - 用于理解中的任一值的模式匹配?