Skip to content

bdsqqq/try

Repository files navigation

Try™

Don't let the Try Catch Tower of Terror destroy your beautiful one liners.

Usage

npm install @bdsqqq/try
import { trytm } from "@bdsqqq/try";

const mockPromise = () => {
  return new Promise<string>((resolve, _) => {
    setTimeout(() => {
      resolve("hello from promise");
    }, 1000);
  });
};

const mockPromiseThatFails = () => {
  return new Promise<string>((_, reject) => {
    setTimeout(() => {
      reject(new Error("hello from promise"));
    }, 1000);
  });
};

const [data, error] = await trytm(mockPromise());
const [data2, error2] = await trytm(mockPromiseThatFails());

Why does this exist?

Async await feels like heaven because it avoids the callback hell or Pyramid of Doom by writing asyncronous code in a line by line format:

function hell() {
   step1((a) => {
      step2((b) => {
         step3((c) => {
            // ...
         })
      })
   })
}

async function heaven(){
   const a = await step1();
   const b = await step2(a);
   const c = await step3(b);
   // ...
}

Until error handling comes into play... Because then you end up with the Try-Catch Tower of Terror, where your beautiful one-liners magically expand to at least 5 lines of code:

async function Terror(){
   let a;
   let b;
   let c;

   try {
      a = await step1();
   } catch (error) {
      handle(error);
   }


   try {
      b = await step2(a);
   } catch (error) {
      handle(error);
   }


   try {
      c = await step3(b);
   } catch (error) {
      handle(error);
   }

   // ...
}

An easy solution would be to append the .catch() method to the end of each promise:

async function easy(){
   const a = await step1().catch(err => handle(err));
   const b = await step2(a).catch(err => handle(err));
   const c = await step3(b).catch(err => handle(err));
   // ...
}

This approach solves the issue but can get a bit repetitive, another approach is to create a function that implements one Try Catch to replace all the others:

import { trytm } from "@bdsqqq/try"

async function awesome() {
   const [aData, aError] = await trytm(step1());
   if(aError) // ...

   const [bData, bError] = await trytm(step2(aData));
   if(bError) // ...

   const [cData, cError] = await trytm(step3(bData));
   if(cError) // ...

   // ...
}

Why does this REALLY exist?

I watched a fireship short and ended up in a rabbit hole to learn how to publish a NPM package. This is still an interesting pattern to use in your codebase but might be best copy pasted instead of being a dependency.

I'll leave the source code here so you don't have to look for the one .ts file in the /src folder:

export const trytm = async <T>(
   promise: Promise<T>,
): Promise<[T, null] | [null, Error]> => {
   try {
      const data = await promise;
      return [data, null];
   } catch (throwable) {
      if (throwable instanceof Error) return [null, throwable];

      throw throwable;
   }
};

Attributions

This code is blatantly stolen from a fireship youtube short, with minor additions to make data infer its typing from the promise passed as an argument.

About

Don't let the Try Catch Tower of Terror destroy your beautiful one liners.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •