Two Tiny Utils for the Result Pattern

12 points by confusedalex


quad
  1. Promise.try is nice too.
  2. safeExec could be stated as try(...).flatten()… and then you only need one helper.
alper

This looks like a great min/max sweet spot? Much better than many of the other Typescript stabs at this I saw.

neilmadden

Maybe I don’t know enough TypeScript but Promise<Result<T>> looks a bit odd to me - isn’t a Promise effectively an async Result already?

chrismorgan

I’d prefer wrapping functions, rather than having double function syntax at every function that uses the pattern. It’ll translate to decorators more nicely, too (should even be able to support that transparently). Just porting tryCatch and its examples (with a tentative rename too, and a more precise TypeScript signature for fun):

export function asResult<TArgs extends unknown[], TReturn>(
    fn: (...args: TArgs) => TReturn | PromiseLike<TReturn>
) => async (...args: TArgs): Promise<Result<Awaited<TReturn>>> => {
    try {
        const result = await fn(...args);
        return { status: "success", result };
    } catch (err: unknown) {
        return { status: "error", err };
    }
};

export const listPizzas = asResult(api.list);

export const getPizza = asResult(async (id: string): Promise<Pizza> => {
    return await api.get(id);
});
ejri

I've been considering adding something like this to my projects, wondering if anyone has thoughts on using something like this vs a library like https://github.com/supermacro/neverthrow

icholy

If I was going to use a pattern like this, I'd probably use a boolean as the discriminator.

type Result<T> = { ok: true; result: T } | { ok: false; err: unknown };

But this is just fighting the language/ecosystem.

rslabbert

For an out of the box experience as a library I've enjoyed true-myth. It has the equivalent to the tryCatch function via safe.