我现在正在学习 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
中使用异步代码时,您首先将代码转换为 Task
或 TaskEither
(稍后会详细介绍)。首先,我们需要一个函数来执行 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/