Error handling without try/catch blocks
Tags: javascript, typescript, programming
Published: 2021-01-20 16:20:12

---
title: Error handling without try/catch blocks
description: When building large applications it might get a bit tedious when you have to wrap lots of parts of the code within _try/catch_. Instead of getting sick of _try/catch_, there is another way of checking if the executable throws an error, using custom error instances.
tags:
  - javascript
  - typescript
  - programming
published: true
---
The `try/catch` statement wraps a code block within a wrapper and catches any exception thrown from that same block. When building large applications it might get a bit tedious when you have to wrap lots of parts of the code within _try/catch_.

Instead of getting sick of _try/catch_, there is another way of checking if the executable throws an error, using custom error instances.

## Building custom error class
```
interface ICustomErrorProps extends Error {
  status?: number;
  data?: any;
}

class CustomError {
  constructor(props: ICustomErrorProps) {
    this.status = props.status;
    this.message = props.message;
    this.data = props.data;
  }

  message: ICustomErrorProps["message"];
  status?: ICustomErrorProps["status"];
  data?: ICustomErrorProps["data"];
}
``` 

The code above is building a custom error class which expects, the usual properties that can be found in an error, e.g. `status`, `message`, `data`.

## Building an Error Validator
By using custom class, it can be easily determined what type of response has been returned by checking the instance of the response. To illustrate how to do this, here is an ErrorValidator, which will determine the type of response.

```
type IResponse<T> = T | CustomError;

class ErrorValidator {
  constructor() {
    this.isError = this.isError.bind(this);
    this.isSuccess = this.isSuccess.bind(this);
  }

  public isError<T>(result: IResponse<T>): result is CustomError {
    return result instanceof CustomError;
  }

  public isSuccess<T>(result: IResponse<T>): result is T {
    return !this.isError(result);
  }
}
```

The `IResponse` type defines what type the response can be - in this case either success `T` or error `CustomError`. 

The `ErrorValidator` has two functions, `isError` and `isSuccess`. The `isError` function is checking if the `instanceof` the object is the `CustomError` that was defined above. 

The TypeScript type predicate `result is CustomError` will automatically cast the `result` to `CustomError` if the returned condition is `true`. 

# ErrorValidator in action 
One way to see this in action is to build an abstraction for an HTTP client. The HTTP client can extend the `ErrorValidator` class so the validation functions can be easily accessible by the client instance.

Here is an example of an HTTP client:
```
class HttpClient extends ErrorValidator {
  public async request<T>(
    url: string,
    options?: RequestInit
  ): Promise<IResponse<T>> {
    return fetch(url, options)
      .then((response) => response.json())
      .then((result: T) => result)
      .catch((error) => new CustomError(error));
  }
}
```
The `request` function of the `HttpClient` is returning a promise of the `IResponse` type defined above. The catch of the `fetch` creates a new instance of the `CustomError` which later on can be validated.

Here is an example of how to consume the `HttpClient`:

```
interface IUserDetails {
  firstName: string;
  lastName: string;
  dob: Date;
}

async function init() {
  const httpClient = new HttpClient();

  const userDetails = await httpClient.request<IUserDetails>(
    "https://my-domain.com/user-details"
  );

  if (httpClient.isError(userDetails)) {
    console.log("An error occurred: ", userDetails.message);
    // Do something with the error
    return;
  }
  console.log("API Response data: ", userDetails);
  // Do something with the success
}
init();
```

The main trick to bear in mind when using the custom error classes is the `instanceof` operator. As this is a pure JavaScript operator the same approach can be taken without TypeScript. The only difference will be that it won't apply static type checking.