Search
⌘K

Try Catch Async

Utility for make async functions not throwable.

Example Usage

tryCatchAsync

Wrap an async function to make it not-throwable, by wrapping it in a try-catch block.

The resulting function:

  • never throws
  • returns a discriminated union on status that can be success | error
  • if the original function throws, returns { status: 'error', error: unknown }
  • if the original function doesn't throw, returns { status: 'success', data: <return type of original fn> }
import { tryCatchAsync } from './try-catch-async';

const result = await tryCatchAsync(
  async () => {
    const isSuccess = Math.random() > 0.5;
    if (!isSuccess) throw new Error('Fake error');
    return {
      message: 'hello',
    };
  }
);

// you must check the discriminated union on "status"
if (result.status === 'error') {
  console.log(result.error);
  return;
}

// so here we know that "status" === 'success' and "data" is defined
const data = result.data;
{
  message: string
}

Dependencies

No dependencies

Auto Install

npx shadcn@latest add https://shadcn-registry-ts.vercel.app/r/util-try-catch-async.json

Manual Install

try-catch-async.ts
type ResultError = {
  status: 'error';
  error: unknown;
};
type ResultSuccess<TData> = {
  status: 'success';
  data: TData;
};

type Result<TSuccessData> = ResultError | ResultSuccess<TSuccessData>;

/**
 * Function that run an asyn cfunction inside a try catch block.
 */
export const tryCatchAsync = async <TReturn>(fn: () => Promise<TReturn>): Promise<Result<TReturn>> => {
  try {
    const data = await fn();
    return { status: 'success', data } as const;
  } catch (error) {
    return { status: 'error', error } as const;
  }
};

Test

try-catch-async.test.ts
import { describe, it, expect } from 'vitest';
import { repeatAsyncFnInParallel } from '../utility-framework/vitest.utils';
// import { calculateFrequenciesStats } from './math';

import { tryCatchAsync } from './try-catch-async';


describe('tryCatchAsync', () => {

  it('do it', async () => {

    const FREQUENCIES = {
      success: 0,
      error: 0
    };

    await repeatAsyncFnInParallel(1_000, async () => {

      const result = await tryCatchAsync(async () => {
        const isSuccess = Math.random() > 0.5;
        if (isSuccess) return { ok: true };
        throw new Error('Fake error');
      });

      expect(result).toBeTypeOf('object');
      expect(result).toHaveProperty('status');
      expect(result.status).oneOf(['success', 'error']);

      if (result.status === 'success') {
        expect(result.data).toBeTypeOf('object');
        expect(result.data).toHaveProperty('ok');
        expect(result.data.ok).toBe(true);

        FREQUENCIES.success++;
      }

      if (result.status === 'error') {
        expect(result.error).toBeInstanceOf(Error);

        FREQUENCIES.error++;
      }
    });

    // check frequencies
    // console.log(calculateFrequenciesStats(FREQUENCIES));
    expect(FREQUENCIES.success).toBeGreaterThan(0);
    expect(FREQUENCIES.error).toBeGreaterThan(0);

  });

});

Command Palette

Search for a command to run...