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: text/0004-interoperable-exceptions.md
+117-4Lines changed: 117 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -11,11 +11,60 @@ Improve exception syntax to ensure exceptions from JavaScript are safely convert
11
11
12
12
## Motivation
13
13
14
-
ReScript provides a convenient exception syntax. But it's not really useful.
14
+
In the JavaScript/TypeScript world, Exceptions are one of the most akward syntax to use.
15
15
16
-
However, in the ReScript ecosystem, the `result` type is generally preferred over exceptions, so this syntax is rarely used.
16
+
- Since JavaScript allows to throw any values, TypeScript only allows `any` or `unknown` as its type. Users need to insert their own runtime validation to safely handle exceptions.
17
+
- Exception handling is only available in the try-catch statement, which is not an expression.
18
+
- Users have to hoist the `let` binding them selves and type inference will not work automatically.
17
19
18
-
On the other hand, since it's not compatible with JavaScript exceptions, there is no way to handle executions that may throw JavaScript exceptions safely with exception syntax.
20
+
### TypeScript examples
21
+
22
+
```ts
23
+
function isTypeError(exn:unknown):exnisTypeError {
24
+
returnexninstanceofTypeError;
25
+
}
26
+
27
+
// Or using third-party validator library for more complex structs.
28
+
import*asSfrom"sury";
29
+
30
+
// E.g. https://nodejs.org/api/errors.html#nodejs-error-codes
31
+
const AccessDeninedErrorSchema =S.schema({
32
+
code: S.literal("ERR_ACCESS_DENINED"),
33
+
errno: S.number,
34
+
message: S.string,
35
+
});
36
+
37
+
let result:ReturnType<typeofmaybeThrow>;
38
+
try {
39
+
result=maybeThrow()
40
+
} catch (exn:unknown) {
41
+
let result =S.safe(() =>S.parseOrThrow(exn, AccessDeninedError));
42
+
if (result.sucess) {
43
+
let error =exn.value;
44
+
// ?^ S.Output<typeof AccessDeninedErrorSchema>
45
+
} elseif (isTypeError(exn)) {
46
+
let error =exn;
47
+
// ?^ TypeError
48
+
}
49
+
throwexn;
50
+
}
51
+
```
52
+
53
+
ReScript have way better exception syntax.
54
+
55
+
```res
56
+
exception AccessDeninedError(exn)
57
+
exception TypeError(exn)
58
+
59
+
let result = try {
60
+
maybeThrow()
61
+
} catch {
62
+
| AccessDeninedError(exn) => // ...
63
+
| TypeError(exn) => // ...
64
+
}
65
+
```
66
+
67
+
But it's not really useful because it's not compatible with JavaScript exceptions, there is no way to handle executions that may throw JavaScript exceptions safely with exception syntax.
19
68
20
69
## Rationale
21
70
@@ -42,14 +91,23 @@ exception Invalid(t1, t2) when fn
42
91
43
92
And the identifier in the `when` clause must be a valid binding with type `unknown => bool`.
44
93
94
+
#### Keyword considerations
95
+
96
+
Keywords are only used in the context of exceptions, so we are free to choose them.
97
+
98
+
-`when`: Highlighting works because we've used it in old syntax.
99
+
-`if`: It would be suitable for reducing the number of tokens, but it can be confusing because it looks different from an if expression grammar.
100
+
-`with`
101
+
-`using`
102
+
45
103
### Semantics
46
104
47
105
The compiler uses the function in the `when` clause to determine if the caught value can be safely coerced to the expected payload type before entering the specific catch branch.
0 commit comments