Цепочка fp-ts TaskEither с Either в правом - PullRequest
3 голосов
/ 02 мая 2020

У меня есть поток из 2 вложенных запросов, где могут быть 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 голосов
/ 03 мая 2020

Не знаю, упрощаете ли вы реальный код, но E.Either<true, false> изоморфно c до 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>>. Вероятно, вам нужно добавить некоторые аннотации типов для проверки типов, я сам не запускал код.

РЕДАКТИРОВАТЬ:

Возможно, вам нужно извлечь лямбда как именованная функция, чтобы получить правильные наборы, что-то вроде этого:

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