Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chain fp-ts TaskEither with Either in right

I have a flow of 2 nested request, where could be 3 different results:

  1. One of requests return Error
  2. User is not Anonymous, return Profile
  3. User is Anonymous, return false

Both requests could throw an error, and becaues of that implements 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)

The first request returns the boolean status of user authorization. Second request loads user profile if the user is authorized.

In return, I want to get the next signature, Error or Either with Anonymous/Profile:

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

I tried to make it this way:

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

But in return, I get E.Either<Error, Profile>, witch not convenient because I have to extract Anonymous status by hands from Error.

How to solve that question?

like image 800
Ivan Tarasov Avatar asked Oct 23 '25 15:10

Ivan Tarasov


1 Answers

Don't know if you oversimplify actual code, but E.Either<true, false> is isomorphic to just boolean, so let's stick with simpler thing.

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

Then you add condition branch based on whether its authed or not and wrap the result of 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))
  )
)

This expression has type TaskEither<Error, Either<false, Profile>>. You probably need to add some type annotations for it to typecheck properly, I haven't run the code myself.

EDIT:

You probably need to extract lambda as named function to get proper typings, something like so:

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)
);
like image 180
MnZrK Avatar answered Oct 25 '25 04:10

MnZrK