Fp-ts: async either.tryCatch (for promises/tasks)

Created on 18 Jul 2017  Â·  15Comments  Â·  Source: gcanti/fp-ts

All 15 comments

@gcanti I've been using something like this in my applications. Do you think it could be added to the library?

export function eitherTryCatchAsync<E, A>(f: Lazy<Promise<A>>): Promise<Either<E, A>> {
    try {
        return f().then(a => either.right<E, A>(a), e => either.left<E, A>(e));
    } catch (e) {
        return Promise.resolve(either.left<E, A>(e));
    }
}

@OliverJAsh the signature is a bit weird

  • the input is lazy but the output isn't
  • how can you produce an E? (indeed since e: any then e => either.left<E, A>(e) and Promise.resolve(either.left<E, A>(e)) are basically unsafe casts)

What about

function tryCatchAsync<E, A>(p: Lazy<Promise<A>>, onerror: (reason: any) => E): Lazy<Promise<Either<E, A>>>

@gcanti Good improvements. That works for me!

So:

import * as either from 'fp-ts/lib/Either';
import { Lazy } from 'fp-ts/lib/function';

import Either = either.Either;

export const eitherTryCatchAsync = <E, A>(
    f: Lazy<Promise<A>>,
    onError: (reason: any) => E,
): Lazy<Promise<Either<E, A>>> => () => {
    try {
        return f().then(a => either.right<E, A>(a), reason => either.left<E, A>(onError(reason)));
    } catch (e) {
        return Promise.resolve(either.left<E, A>(e));
    }
};

I wonder, what the try..catch is for? AFAIK both f(), a => either.right<E, A>(a) can't fail

@gcanti I believe f could throw. For example:

const someFnThatThrowsSynchronously = () => {
    throw new Error();
}

const fn: Lazy<Promise<string>> = () => {
    someFnThatThrowsSynchronously();
    return Promise.resolve('foo');
}

Ah, I see. Though ideally a possible failure should be encoded in the type system (with Option/Either).

So shouldn't fn be responsible of handling a possible error? Either changing the signature

const someFnThatThrowsSynchronously = () => {
    throw new Error();
}

const fn: Lazy<Option<Promise<string>>> = () => {
  try {
    someFnThatThrowsSynchronously();
    return some(Promise.resolve('foo'))
  } catch (e) {
    return none
  }
}

or rejecting the promise

const someFnThatThrowsSynchronously = () => {
    throw new Error();
}

const fn: Lazy<Option<Promise<string>>> = () => {
  try {
    someFnThatThrowsSynchronously();
    return Promise.resolve('foo')
  } catch (e) {
    return Promise.reject(e)
  }
}

I see. You could have a higher-order function that normalizes promise-returning functions so any exceptions are returned as rejected promises. Then, the resulting function could be passed into tryCatchAsync (without a try/catch around fn).

I think it is identical to taskEither.fromPromise, except I think there should be some flexibility in the return value:

  • Promise<Either<L, A>> — perhaps this could be provided by either?
  • Task<Either<L, A>> — perhaps this could be provided by task?
  • TaskEither<L, A>— this is already provided by taskEither
  • Promise> — perhaps this could be provided by either? Not sure (*)
  • Task> — perhaps this could be provided by task? :+1:
  • TaskEither<>— this is already provided by taskEither :+1:

(*) Either would contain a function coupled with a Promise implementation (see https://github.com/gcanti/fp-ts/issues/87). @leemhenson what do you think? Any suggestion?

Hi. I have small question: I need to do fetch and then validate response with io-ts. Is there more elegant way to do this, then

  request()
    .then(result =>
      result.fold(
        error => store.dispatch(Failed()),
        data => store.dispatch(Ok(data))
      )
    )
    .catch(error => store.dispatch(Failed()));

export const getJson = (url: string) => {
  return new task.Task(() => fetch(url))
    .map(parseJsonFromResponse)
    .map(requierRootObject);
};

export const request = () => {
  return getJson(`/api/prices.json`)
    .map(decodePriceResponse) //
    .run();
};

// PriceInterface is io-ts type
export const decodePriceResponse = (obj: {}) => t.validate(obj, PriceInterface);

I was not able to figure out how to use the library to handle async/await for third party libraries that do not use fp-ts. Below function works for me. I am not sure if it is the FP way, however. Can anyone suggest a better approach @OliverJAsh @gcanti @stereobooster ?

export async function eitherTryCatchAsync<E, A>(
  f: () => Promise<A>,
): Promise<either.Either<E, A>> {
  try {
    let result = await f();
    return Promise.resolve(either.right<E, A>(result))
  } catch (reason) {
    return Promise.resolve(either.left<E, A>(reason))
  }
};

@navinkumarr usually the FP way is to prefer Task to Promise

I would prefer to use Observables and use RxJs Bindings

On Sun, 21 Oct 2018, 22:16 navinkumarr, notifications@github.com wrote:

I was not able to figure out how to use the library to handle async/await
for third party libraries that do not use fp-ts. Below function works for
me. I am not sure if it is the FP way, however. Can anyone suggest a better
approach @OliverJAsh https://github.com/OliverJAsh @gcanti
https://github.com/gcanti @stereobooster
https://github.com/stereobooster ?

export async function eitherTryCatchAsync(
f: () => Promise,
): Promise> {
try {
let result = await f();
return Promise.resolve(either.right(result))
} catch (reason) {
return Promise.resolve(either.left(reason))
}
};

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/gcanti/fp-ts/issues/159#issuecomment-431684241, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AO6DzNaoI4p4QSJGWmMpRIrxIb8qRuu-ks5unKTJgaJpZM4ObzmL
.

You can just take a look at fp-ts-rxjs

There is currently no tryCatch function for rxjs but you can build your own one:

const tryCatch = <L, R>(f: () => Promise<R>): Observable<Either<L, R>> =>
  defer(f).pipe(
    map((r) => right<L, R>(r)),
    catchError((l) => of(left<L, R>(l)))
  );
Was this page helpful?
0 / 5 - 0 ratings

Related issues

josete89 picture josete89  Â·  3Comments

miguelferraro picture miguelferraro  Â·  3Comments

steida picture steida  Â·  4Comments

Crashthatch picture Crashthatch  Â·  4Comments

amaurymartiny picture amaurymartiny  Â·  4Comments