typescript - 从 fp-ts 中的项目数组中删除选项
问题描述
假设我有以下类型:
type ValidatedInput = Readonly<{
id: string
}>
type GetStructures = (id: string) => TaskEither<ServiceError, ReadonlyArray<SomeStructure>>
type GetOtherStructures = (ids: ReadonlyArray<string>) => TaskEither<ServiceError, ReadonlyArray<SomeOtherStructure>>
type LookupThings = (initialInput: ReadonlyArray<SomeStructure>, additionalInput: ReadonlyArray<SomeOtherStructure>) => TaskEither<ServiceError, ReadonlyArray<Option<ResponseType>>>
export type Deps = Readonly<{
getStructures: GetStructures
getOtherStructures: GetOtherStructures
lookupThings: LookupThings
}>
export type Ctx<T> = ReaderTaskEither<Deps, Error, T>
以及以下错误处理助手:
type Code = 'INVALID_ENTITY' | 'INVALID_API_KEY'
export const fromCode = (code: Code): Error => ({
tag: 'validation',
code
})
然后我创建一个像这样的函数:
const constructFullData = (input: ValidatedInput): Ctx<ReadonlyArray<Option<ResponseType>>> => (
(deps: Deps): TE.TaskEither<Error, ReadonlyArray<Option<ResponseType>>> => (
pipe(
deps.getStructures(input.id),
TE.map((structs) => pipe(
deps.getOtherStructures([structs[0].higherOrderId]),
TE.chain(otherStructs => pipe(
deps.lookupThings(structs, otherStructs),
TE.chain(results => {
if (results.filter(isNone).length !== results.length) {
return TE.left(fromCode('INVALID_ENTITY')) // I'm not sure what a better way to filter this is. Ideally the return type of this function wouldn't have an Option in it
} else {
return TE.right(results)
}
})
))
)),
TE.flatten
)
)
)
这一切都编译得很好,但我真正想要的是返回一个没有过滤掉的数组,如果没有则引发适当的错误!
天真的方法是将 Right 路径的返回更改为:
return TE.right(results.map(u => u.value))
但这不会编译,抛出以下错误:
Property 'value' does not exist on type 'None'.
64 return TE.right(usagesWithDrones.map(u => u.value))
如何应用这种过滤?
解决方案
将选项列表折叠成一个呢?就像是:
import * as TE from "fp-ts/TaskEither";
import * as ROA from "fp-ts/ReadonlyArray";
import * as T from "fp-ts/Task";
import * as E from "fp-ts/Either";
import * as O from "fp-ts/Option";
import { pipe } from "fp-ts/pipeable";
import { constant, flow, Lazy } from "fp-ts/lib/function";
const value = TE.right<"ThisErrorDoesntExist", readonly O.Option<number>[]>(
ROA.of(O.some(42))
);
const arrayOfNumbersMonoid = ROA.getMonoid<number>();
type Result = E.Either<"FoundNoneInList", readonly number[]>;
const rightEmptyListOfNumbers: Result = E.right([]);
const leftFoundNoneInList: Lazy<Result> = constant(E.left("FoundNoneInList"));
const reducer = (acc: typeof rightEmptyListOfNumbers, next: O.Option<number>) =>
pipe(
acc,
E.chain((numbers) =>
pipe(
next,
O.fold(
leftFoundNoneInList,
flow(ROA.of, (n) => arrayOfNumbersMonoid.concat(numbers, n), E.right)
)
)
)
);
const result = pipe(
value,
T.map(E.chainW(ROA.reduce(rightEmptyListOfNumbers, reducer)))
);
推荐阅读
- javascript - 如何从反应映射组件更新状态
- javascript - 将 useState 属性传递给
在 React Native 中使用 React Navigation - vba - 如何通过 vba 代码按照幻灯片标题插入图像
- java - 使用 Java 变量的值创建对象
- php - 无法在 Akeneo 中获取带有查询字符串的页面
- dataset - 我在哪里可以找到有效的 6 或 9 DOF IMU 数据集?
- python-3.x - 如何使我的 OpenFaaS python 中的同级文件夹在函数构建和部署时可见
- python - 如何将通过 GraphQL API 检索到的数据正确格式化为数据框?
- vue.js - 如何将 Vue 2 x 转换为 Vue 3 x?
- sql - 如何获得两个玩家一起玩的总胜利?