Better Error Handling

javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

There's a saying in software development that exceptions are for exceptional circumstances, and that is exactly what we will cover in this lesson. We will look at a few JavaScript examples and even discuss how this relates to Asing Await. So let's go. We bring in some utilities from a vendor file and a key utility over here is the email validator. And when we say validator, we basically mean that it's going to take a value and it's either going to return true or false based on if it is a valid email or not. Now our objective is to do a nice a p I design for this validate function that takes a value and a set of validators and then has to indicate if the value is

00:37

valid. And if it is not valid, it wants to provide a custom error message. Now, determining if it is valid or invalid is actually quite easy. We can simply loop through all of the validators, invoke them with the value and see if any of them says that it is false. Now, there are a number of validation libraries out there that get the next step wrong. If the value is valid, they will return the valid value, otherwise they will throw an error. Now, even though you might think that this is perfectly fine, let's look at an example that demonstrates why this is not a good idea. Consider the user that wants to write the submit function that takes an email,

01:11

runs them through the validate function and wants to see if it comes out as valid or not. Because we've gone with an exception throwing model, we have to write our call to validate with the try-catch. Now, there are a few reasons why this is not ideal Within the catch, there is no guarantee that the error is coming from the validate function as they might have just made a mistake within the try block themselves. Now, that's not true for this particular case. But another issue that can happen is that the email validator might throw an exception when it is invoked by the validate function. And now when the validate function calls this particular validator,

01:44

this will still get caught by our catch and we would expect just the error from the else block. But we are actually getting an error from the email validator and this has nothing to do with the email being invalid. Perhaps there is a bug within the email validator and instead of being caught as a bug within our code, is it actually being converted into an error in the user's input? Now the alternative approach is quite simple. You can perhaps return a bullion value that is true for valid and false for invalid. Or if you do want to return a value or an error message, you can return to different kinds of objects. If it is a valid value, you return an object containing the value member. And if it is invalid,

02:21

you return an object containing an error message. We simply annotate our function with this new type and then replace the return of the value with the return of an object containing the string value and then replace the throw with an object that contains the error string. And now we can modify the code within our submit function to be a bit more reliable as it's not catching everything that might go wrong within our call stack. We simply check the results that is returned from the validate function. If it has an error property, this means that it is not a valid value and we can notify the user of the error within the email. Otherwise we simply save the result of value.

02:57

So really the key Takeaway over here is that we shouldn't be throwing an error in our code unless we want it to bubble far, far away all the way to our program's exit log. Now things get even a bit more interesting when you consider Async away. So let's take a look. We will look at a simpler example with Async Away because even people that would never throw an exception would still quite happily reject a promise. Haing have a function called is negative, that takes a value. And by returning a promise and based on some super complicated complex logic, we would either resolve it with the value or we will reject the promise with a

03:31

custom error message. Now, using promise resolution and promise rejection to separate different kinds of returns is not a good idea. Here's some code that is a similar kind of thing that we did before. We, we take an input value, we want to see if it is negative or not using this is negative utility and now we have to wrap it in a try-catch if you want to get this error message. Because when you await a promise that is going to reject it is essentially going to throw an exception at that particular point in the call stack. Now, the proper approach will be very similar to the approach that we took in the synchronous version. Essentially,

04:03

you should think of the return statement within a synchronous version, the same as a promised resolution and a throw in the synchronous version, the same as a promised rejection. So we replace our rejection with the resolution containing an object that has the error property and the successful return as a resolution containing the value property. And now within our Async eight, we can do the same thing that we did before. We no longer need the try-catch. We simply get the result, see if it has the error property, and then notify the user about the error. Otherwise, we save the input. So to recap, don't throw errors unless you need to.

04:39

And if you are working with Async Away, which most of us are, show your rejections the same love that you would show your throw statements. And if you are working with someone that loves to throw and reject, then share this with you, with them. Smash the like and subscribe for more content like this. And I will see you in the next one.