简体   繁体   English

从 fp-ts 中的项目数组中删除选项

[英]Remove Options from array of items in fp-ts

Say I have the following types:假设我有以下类型:

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>

And the following error handling helper:以及以下错误处理助手:

type Code = 'INVALID_ENTITY' | 'INVALID_API_KEY'
export const fromCode = (code: Code): Error => ({
  tag: 'validation',
  code
})

I then create a function like so:然后我像这样创建一个 function :

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

This all compiles just fine, but what I really want is to return an array with none's filtered out, and raise the appropriate error if there is a none!这一切都编译得很好,但我真正想要的是返回一个没有过滤掉的数组,如果没有则引发适当的错误!

The naive approach is to change the return of the Right path to:天真的方法是将 Right 路径的返回更改为:

return TE.right(results.map(u => u.value))

But this does not compile, throwing the following error:但这不会编译,抛出以下错误:

Property 'value' does not exist on type 'None'.
64               return TE.right(usagesWithDrones.map(u => u.value))

How can apply this kind of filtering?如何应用这种过滤?

What about folding the list of options into an either?将选项列表折叠成一个呢? Something like:就像是:

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

The easiest way to remove options from an array is to use the compact function (see a simple example below).从阵列中删除选项的最简单方法是使用紧凑型 function(参见下面的简单示例)。 The compact function is present in most of the fp-ts libs.紧凑型 function 存在于大多数 fp-ts 库中。

import { Option, some, none } from "fp-ts/lib/Option"
import { compact } from "fp-ts/lib/Array"

const initialArray = [1, 2, 3, 4, 5, 6, 7]

const arrayWithOptions: Option<number>[] = initialArray.map((el) => {
  if (el % 2 === 0) return some(el)
  else return none
})

const finalArray: number[] = compact(arrayWithOptions)

console.log(finalArray)

The console log will print [2,4,6].控制台日志将打印 [2,4,6]。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM