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
-[Expressions are evaluated in a self-contained `try/catch` block](#expressions-are-evaluated-in-a-self-contained-trycatch-block)
27
30
-[Can be inlined.](#can-be-inlined)
@@ -31,10 +34,12 @@ Only the `catch (error) {}` block represents actual control flow, while no progr
31
34
-[Never throws](#never-throws)
32
35
-[Parenthesis Required for Object Literals](#parenthesis-required-for-object-literals)
33
36
-[Void Operations](#void-operations)
34
-
-[Result class](#result-class)
37
+
-[Result Class](#result-class)
38
+
-[Instance Structure](#instance-structure)
39
+
-[Iterable](#iterable)
40
+
-[Manual Creation](#manual-creation)
35
41
-[Why Not `data` First?](#why-not-data-first)
36
42
-[The Need for an `ok` Value](#the-need-for-an-ok-value)
37
-
-[Caller's Approach](#callers-approach)
38
43
-[Why a Proposal?](#why-a-proposal)
39
44
-[Help Us Improve This Proposal](#help-us-improve-this-proposal)
40
45
-[Authors](#authors)
@@ -124,11 +129,55 @@ A `try` statement provide significant flexibility and arguably result in more re
124
129
125
130
<br />
126
131
132
+
## Caller's Approach
133
+
134
+
JavaScript has evolved over decades, with countless libraries and codebases built on top of one another. Any new feature that does not consider compatibility with existing code risks negatively impacting its adoption, as refactoring functional, legacy code simply to accommodate a new feature is often an unjustifiable cost.
135
+
136
+
With that in mind, improvements in error handling can be approached in two ways:
137
+
138
+
1.**At the caller's level**:
139
+
140
+
```js
141
+
try {
142
+
constresult=work()
143
+
} catch (error) {
144
+
console.error(error)
145
+
}
146
+
```
147
+
148
+
2.**At the callee's level**:
149
+
150
+
```js
151
+
functionwork() {
152
+
// Performs some operation
153
+
154
+
if (error) {
155
+
return { status:"error", error }
156
+
} else {
157
+
return { status:"ok", data }
158
+
}
159
+
}
160
+
```
161
+
162
+
Both approaches achieve the same goal, but the second one requires refactoring all implementations into a new format. This is how languages like Go and Rust handle errors, returning a tuple of an error and a value or a `Result` object, respectively. While the callee-based approach can arguably be better, it succeeded in those languages because it was adopted from the very beginning, rather than introduced as a later addition.
163
+
164
+
This proposal accounts for this by moving the transformation of errors into values to the **caller** level, preserving the familiar semantics and placement of `try/catch`. This approach ensures backward compatibility with existing code.
165
+
166
+
Breaking compatibility is unacceptable for platforms like Node.js or libraries. Consequently, a callee-based approach would likely never be adopted for functions like `fetch` or `fs.readFile`, as it would disrupt existing codebases. Ironically, these are precisely the kinds of functions where improved error handling is most needed.
167
+
168
+
<br />
169
+
127
170
## What This Proposal Does Not Aim to Solve
128
171
129
-
1.**Strict Type Enforcement for Errors**: The `throw` statement in JavaScript can throw any type of value. This proposal does not impose type safety on error handling and will not introduce types into the language. For more information, see [microsoft/typescript#13219](https://github.com/Microsoft/TypeScript/issues/13219). _(This also means no generic error type for [Result](#result-class))_
172
+
### Strict Type Enforcement for Errors
173
+
174
+
The `throw` statement in JavaScript can throw any type of value. This proposal does not impose nor proposes any kind safety on error handling.
175
+
176
+
For more information, see [microsoft/typescript#13219](https://github.com/Microsoft/TypeScript/issues/13219). _(This also means no generic error type for the proposed [Result](#result-class) class)_
177
+
178
+
### Automatic Error Handling
130
179
131
-
2.**Automatic Error Handling**: While this proposal facilitates error handling, it does not automatically handle errors for you. You will still need to write the necessary code to manage errors the proposal simply aims to make this process easier and more consistent.
180
+
While this proposal facilitates error handling, it does not automatically handle errors for you. You will still need to write the necessary code to manage errors the proposal simply aims to make this process easier and more consistent.
132
181
133
182
<br />
134
183
@@ -304,48 +353,51 @@ function work() {
304
353
305
354
<br />
306
355
307
-
## Result class
356
+
## Result Class
308
357
309
358
> Please see [`polyfill.d.ts`](./polyfill.d.ts) and [`polyfill.js`](./polyfill.js) for a basic implementation of the `Result` class.
310
359
311
360
The `Result` class represents the form of the value returned by the `try` operator.
312
361
313
-
1. **Structure of a `Result` Instance**
314
-
A `Result` instance contains three properties:
362
+
### Instance Structure
315
363
316
-
- **`ok`**: A boolean indicating whether the expression executed successfully.
317
-
- **`error`**: The error thrown during execution, or `undefined` if no error occurred.
318
-
- **`value`**: The data returned from the execution, or `undefined` if an error occurred.
364
+
A `Result` instance contains three properties:
319
365
320
-
Example usage:
366
+
- **`ok`**: A boolean indicating whether the expression executed successfully.
367
+
- **`error`**: The error thrown during execution, or `undefined` if no error occurred.
368
+
- **`value`**: The data returned from the execution, or `undefined` if an error occurred.
321
369
322
-
```js
323
-
constresult=trysomething()
370
+
Example usage:
324
371
325
-
if (result.ok) {
326
-
console.log(result.value)
327
-
} else {
328
-
console.error(result.error)
329
-
}
330
-
```
372
+
```js
373
+
constresult=trysomething()
374
+
375
+
if (result.ok) {
376
+
console.log(result.value)
377
+
} else {
378
+
console.error(result.error)
379
+
}
380
+
```
331
381
332
-
2. **Iterable Behavior**
333
-
A `Result` instance is iterable, enabling destructuring and different variable names:
You can also create a `Result` instance manually using its constructor or static methods:
393
+
394
+
```js
395
+
// Creating a successful result
396
+
constresult=Result.ok(value)
397
+
398
+
// Creating an error result
399
+
constresult=Result.error(error)
400
+
```
349
401
350
402
<br />
351
403
@@ -421,44 +473,6 @@ For a more in-depth explanation of this decision, refer to [GitHub Issue #30](ht
421
473
422
474
<br />
423
475
424
-
## Caller's Approach
425
-
426
-
JavaScript has evolved over decades, with countless libraries and codebases built on top of one another. Any new feature that does not consider compatibility with existing code risks negatively impacting its adoption, as refactoring functional, legacy code simply to accommodate a new feature is often an unjustifiable cost.
427
-
428
-
With that in mind, improvements in error handling can be approached in two ways:
429
-
430
-
1. **At the caller's level**:
431
-
432
-
```js
433
-
try {
434
-
constresult=work()
435
-
} catch (error) {
436
-
console.error(error)
437
-
}
438
-
```
439
-
440
-
2. **At the callee's level**:
441
-
442
-
```js
443
-
functionwork() {
444
-
// Performs some operation
445
-
446
-
if (error) {
447
-
return { status:"error", error }
448
-
} else {
449
-
return { status:"ok", data }
450
-
}
451
-
}
452
-
```
453
-
454
-
Both approaches achieve the same goal, but the second one requires refactoring all implementations into a new format. This is how languages like Go and Rust handle errors, returning a tuple of an error and a value or a `Result` object, respectively. While the callee-based approach can arguably be better, it succeeded in those languages because it was adopted from the very beginning, rather than introduced as a later addition.
455
-
456
-
This proposal accounts for this by moving the transformation of errors into values to the **caller** level, preserving the familiar semantics and placement of `try/catch`. This approach ensures backward compatibility with existing code.
457
-
458
-
Breaking compatibility is unacceptable for platforms like Node.js or libraries. Consequently, a callee-based approach would likely never be adopted for functions like `fetch` or `fs.readFile`, as it would disrupt existing codebases. Ironically, these are precisely the kinds of functions where improved error handling is most needed.
459
-
460
-
<br />
461
-
462
476
## Why a Proposal?
463
477
464
478
A proposal doesn’t need to introduce a feature that is entirely impossible to achieve otherwise. In fact, most recent proposals primarily reduce the complexity of tasks that are already achievable by providing built-in conveniences.
0 commit comments