将fp-ts TaskEither与右边的Either链接

时间:2020-05-02 13:02:28

标签: javascript typescript functional-programming fp-ts

我有两个嵌套请求流,其中可能有3个不同的结果:

  1. 其中一个请求返回错误
  2. 用户不是匿名用户,返回个人资料
  3. 用户为匿名用户,返回false

两个请求都可能引发错误,并且由于该错误实现了TaskEither

const isAuth = ():TE.TaskEither<Error, E.Either<true, false>>  
   => TE.tryCatch(() => Promise(...), E.toError)
const getProfile = ():TE.TaskEither<Error, Profile>  
   => TE.tryCatch(() => Promise(...), E.toError)

第一个请求返回用户授权的布尔状态。如果用户获得授权,则第二个请求会加载用户个人资料

作为回报,我想获得下一个签名,“错误”或“匿名/个人资料”:

E.Either<Error, E.Either<false, Profile>>

我试图做到这一点:

pipe(
    isAuth()
    TE.chain(item => pipe(
      TE.fromEither(item),
      TE.mapLeft(() => Error('Anonimous')),
      TE.chain(getProfile)
    ))
  )

但是作为回报,我得到E.Either<Error, Profile>,这很不方便,因为我必须从Anonymous中手动提取Error的状态。

如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

不知道您是否简化了实际代码,但是E.Either<true, false>boolean是同构的,所以让我们坚持简单些。

declare const isAuth: () => TE.TaskEither<Error, boolean>;
declare const getProfile: () => TE.TaskEither<Error, Profile>;

然后,根据条件分支是否经过验证添加条件分支,并包装getProfile的结果:

pipe(
  isAuth(),
  TE.chain(authed => authed 
    ? pipe(getProfile(), TE.map(E.right)) // wrap the returned value of `getProfile` in `Either` inside the `TaskEither`
    : TE.right(E.left(false))
  )
)

此表达式的类型为TaskEither<Error, Either<false, Profile>>。您可能需要为其添加一些类型注释以进行正确的类型检查,我自己没有运行代码。

编辑:

您可能需要提取lambda作为命名函数以获得正确的输入,诸如此类:

const tryGetProfile: (authed: boolean) => TE.TaskEither<Error, E.Either<false, Profile>> = authed
  ? pipe(getProfile(), TE.map(E.right))
  : TE.right(E.left(false));

const result: TE.TaskEither<Error, E.Either<false, Profile>> = pipe(
  isAuth(),
  TE.chain(tryGetProfile)
);