Advanced try/catch/finally in Javascript and Typescript

Take a detailed look at the implementation of a try-catch-finally-block

Error-handling in Javascript & Typescript

Whenever an error happens at runtime, it gets “thrown” in Javascript and Typescript, as it’s the case in most programming languages. Unhandled thrown errors will lead to a crash of your app or service, thus to the worst user experience possible. If an error happens, any unsaved progress is lost and users might potentially start a long process (for example, if a user was enrolling to a platform by providing lots of information) all over again. The result is that those users will most likely never use your product again, as trust has been lost.

To handle such cases, an error can be “catched”. To catch errors in Javascript and Typescript, you simply wrap your code in a “try”-block, followed by a “catch”-block.

async function getData(){
  try {
    // Call a dummy async 'fetch'-functoin
    const result = await fetch();
    return { result };
  } catch(error) {
    return { error };
  }
}

// ... later in your code ....

const { result, error } = await getData();

if (error){
  // ... handle error case.
}

// Access the results.

The result is that the error won’t propagate through the whole system, which leads to the crash, but will be handled directly in the scope of your code. The app or service won’t crash and a mitigation strategy to process the error can be applied.

Special handling with the “finally”-block

As an extra step to handle errors, Javascript and Typescript provide an additional “finally”-keyword. Such a “finally”-block executes any code within its scope after both the “try”-block as well as the “catch”-block have executed (if an error happened).

// This function is absolutely save
// to call. It fetches some data and 
// optionally catches a potential error.
//
// After everything's done, a 'finally'
// sends the error to our backend for logs,
// if there was any.
async function getData(){
  // In this case, we store the result
  // and error in mutable variables,
  // then return both.
  let result: Result;
  let error: Error;
  
  try {
    // Call a dummy async 'fetch'-function
    result = await fetch();
  } catch(e) {
    error = e;
  } finally {
    // After the whole try/catch has been
    // processed, we can log the error.
    if(error){
      await trackErrorInCloud(error);
    }
  }
  
  return { result, error };
}

// ... same as before ...

But wait, there’s more! Did you know the “finally”-block gets executed even if you return a result in the “try”- or “catch”-block? Here's an example of what I mean by that.

// Same as the example before, but
// now we directly return from within
// each code block. And this is where
// a side effect can happen.
async function getData(){
  try {
    const result = await fetch();
    return { result };
  } catch(error) {
    return { error }
  } finally {
    //
    // WATCH OUT!
    //
    // Just for demo purpose, but this
    // line of code will override both
    // the return in 'try' as well as 'catch'!
    //
    // Returning inside of 'finally' is therefore
    // dangerous and will lead to hard-to-debug 
    // issues.
    return { finally: true };
  }
}

// data === { finally: true }
const data = await getData();
// Here's a better use case for
// finally.
async function getData(){
  let error: Error;
  
  try {
    const result = await fetch();
    return { result };
  } catch(e) {
    error = e;
    return { error }
  } finally {
    // No return in finally,
    // so it's safe to use.
    if(error){
      await logInCloud()
    }
  }
}

// if no error === { result: ... }
// if error === { error: ... }
const data = await getData();

Summary

As you’ve seen, handling errors in Javascript and Typescript is quite easy and avoids a complete crash of your application. The special handling of returning results in the “try”- and “catch”-blocks is good to know when using the "finally"-block, but shouldn’t be abused to avoid implementing your code in an anti-pattern style.

Suggestions

Related

Languages