You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/10-error-handling/2-custom-errors/article.md
+9-14Lines changed: 9 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -17,30 +17,26 @@ Here's an example of how a valid `json` may look:
17
17
let json =`{ "name": "John", "age": 30 }`;
18
18
```
19
19
20
-
Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`.
21
-
22
-
But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users.
20
+
Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users.
23
21
24
22
Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field.
25
23
26
24
Our `ValidationError` class should inherit from the built-in `Error` class.
27
25
28
-
That class is built-in, but we should have its approximate code before our eyes, to understand what we're extending.
29
-
30
-
So here you are:
26
+
That class is built-in, here's it approximate code, for us to understand what we're extending:
31
27
32
28
```js
33
29
// The "pseudocode" for the built-in Error class defined by JavaScript itself
34
30
classError {
35
31
constructor(message) {
36
32
this.message= message;
37
33
this.name="Error"; // (different names for different built-in error classes)
38
-
this.stack=<nested calls>; // non-standard, but most environments support it
34
+
this.stack=<call stack>; // non-standard, but most environments support it
39
35
}
40
36
}
41
37
```
42
38
43
-
Now let's go on and inherit `ValidationError` from it:
39
+
Now let's inherit `ValidationError` from it and try it in action:
44
40
45
41
```js run untrusted
46
42
*!*
@@ -65,10 +61,9 @@ try {
65
61
}
66
62
```
67
63
68
-
Please take a look at the constructor:
64
+
Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property.
69
65
70
-
1. In the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property.
71
-
2. The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value.
66
+
The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value.
72
67
73
68
Let's try to use it in `readUser(json)`:
74
69
@@ -185,7 +180,7 @@ try {
185
180
186
181
The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `newPropertyRequiredError(property)`. The human-readable `message` is generated by the constructor.
187
182
188
-
Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name=<classname>` in every custom error class. But there's a way out. We can make our own "basic error" class that removes this burden from our shoulders by using `this.constructor.name` for `this.name` in its constructor. And then inherit all ours custom errors from it.
183
+
Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name=<classname>` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name=this.constructor.name`. And then inherit all ours custom errors from it.
189
184
190
185
Let's call it `MyError`.
191
186
@@ -218,9 +213,9 @@ Now custom errors are much shorter, especially `ValidationError`, as we got rid
218
213
219
214
## Wrapping exceptions
220
215
221
-
The purpose of the function `readUser` in the code above is "to read the user data", right? There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors.
216
+
The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors.
222
217
223
-
The code which calls `readUser` should handle these errors. Right now it uses multiple `if` in the `catch` block to check for different error types and rethrow the unknown ones. But if `readUser` function generates several kinds of errors -- then we should ask ourselves: do we really want to check for all error types one-by-one in every code that calls `readUser`?
218
+
The code which calls `readUser` should handle these errors. Right now it uses multiple `if` in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. But if `readUser` function generates several kinds of errors -- then we should ask ourselves: do we really want to check for all error types one-by-one in every code that calls `readUser`?
224
219
225
220
Often the answer is "No": the outer code wants to be "one level above all that". It wants to have some kind of "data reading error". Why exactly it happened -- is often irrelevant (the error message describes it). Or, even better if there is a way to get error details, but only if we need to.
0 commit comments