Skip to content

Commit e68abfd

Browse files
Error handling example
1 parent 3586655 commit e68abfd

File tree

1 file changed

+89
-3
lines changed

1 file changed

+89
-3
lines changed

_blogposts/2025-09-01-let-unwrap.mdx

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
author: rescript-team
3-
date: "2025-09-01"
3+
date: "2025-10-14"
4+
previewImg: /static/blog/rescript-12-let-unwrap.jpg
45
badge: roadmap
56
title: let?
67
description: |
@@ -55,6 +56,7 @@ Let's rewrite the above example again with our new syntax:
5556
let getUser = async (id) => {
5657
let? Ok(user) = await fetchUser(id)
5758
let? Ok(decodedUser) = decodeUser(user)
59+
Console.log(`Got user ${decodedUser.name}!`)
5860
let? Ok() = await ensureUserActive(decodedUser)
5961
Ok(decodedUser)
6062
}
@@ -96,9 +98,93 @@ let? Ok(user) = await fetchUser("1")
9698
// ^^^^^^^ ERROR: `let?` is not allowed for top-level bindings.
9799
```
98100

99-
<!-- TODO: demonstrate error handling with polymorphic variants a little more -->
101+
### A full example with error handling
100102

101-
### How to enable it
103+
<CodeTab labels={["ReScript", "JS Output"]} experiments="LetUnwrap">
104+
105+
```rescript
106+
type user = {
107+
id: string,
108+
name: string,
109+
token: string,
110+
}
111+
112+
external fetchUser: string => promise<
113+
result<JSON.t, [> #NetworkError | #UserNotFound | #Unauthorized]>,
114+
> = "fetchUser"
115+
116+
external decodeUser: JSON.t => result<user, [> #DecodeError]> = "decodeUser"
117+
118+
external ensureUserActive: user => promise<result<unit, [> #UserNotActive]>> =
119+
"ensureUserActive"
120+
121+
let getUser = async id => {
122+
let? Ok(user) = await fetchUser(id)
123+
let? Ok(decodedUser) = decodeUser(user)
124+
Console.log(`Got user ${decodedUser.name}!`)
125+
let? Ok() = await ensureUserActive(decodedUser)
126+
Ok(decodedUser)
127+
}
128+
129+
// ERROR!
130+
// You forgot to handle a possible case here, for example:
131+
// | Error(#Unauthorized | #UserNotFound | #DecodeError | #UserNotActive)
132+
let main = async () => {
133+
switch await getUser("123") {
134+
| Ok(user) => Console.log(user)
135+
| Error(#NetworkError) => Console.error("Uh-oh, network error...")
136+
}
137+
}
138+
```
139+
140+
```js
141+
async function getUser(id) {
142+
let e = await fetchUser(id);
143+
if (e.TAG !== "Ok") {
144+
return e;
145+
}
146+
let e$1 = decodeUser(e._0);
147+
if (e$1.TAG !== "Ok") {
148+
return e$1;
149+
}
150+
let decodedUser = e$1._0;
151+
console.log(`Got user ` + decodedUser.name + `!`);
152+
let e$2 = await ensureUserActive(decodedUser);
153+
if (e$2.TAG === "Ok") {
154+
return {
155+
TAG: "Ok",
156+
_0: decodedUser
157+
};
158+
} else {
159+
return e$2;
160+
}
161+
}
162+
163+
async function main() {
164+
let user = await getUser("123");
165+
if (user.TAG === "Ok") {
166+
console.log(user._0);
167+
return;
168+
}
169+
if (user._0 === "NetworkError") {
170+
console.error("Uh-oh, network error...");
171+
return;
172+
}
173+
throw {
174+
RE_EXN_ID: "Match_failure",
175+
_1: [
176+
"playground.res",
177+
28,
178+
2
179+
],
180+
Error: new Error()
181+
};
182+
}
183+
```
184+
185+
</CodeTab>
186+
187+
## Experimental features
102188

103189
We have added an **experimental-features infrastructure** to the toolchain. If you use the new build system that comes with ReScript 12 by default, you can enable it in `rescript.json` like so:
104190

0 commit comments

Comments
 (0)