Exploring ReScript Exception Handling
Kevan Stannard
Posted on November 21, 2020
Introduction
A brief exploration of some ReScript exception handling.
Hopefully this provides some useful examples of ReScript error handling.
ReScript version: bs-platform@8.3.3
Handling JavaScript exceptions thrown from JavaScript
Write a JS function that throws an error, and add a binding for it.
%%raw(`
function a() {
throw new Error("An error occurred")
}
`)
@bs.val external a: unit => unit = "a"
Catch the error using try/catch.
try {
a()
} catch {
| Js.Exn.Error(error) => {
// error: Js.Exn.t
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
}
Or, catch the error using switch
and matching on the Js.Exn.Error
type:
switch a() {
| exception Js.Exn.Error(error) => {
// error: Js.Exn.t
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| () => ()
}
Or, catch the error using switch
, matching on any exception type, and detect the Js.Exn.t
type.
switch a() {
| exception error => {
// error: exn
let optError = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
// error: Js.Exn.t
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Unknown error")
}
}
| () => ()
}
Handling JavaScript exceptions thrown from ReScript
Write a function that throws a JavaScript exception:
let b = (): unit => {
// Equivalent to throw new Error("An error occurred")
Js.Exn.raiseError("An error occurred")
}
Handling these errors is identical to when the exception is thrown from JavaScript.
Catch the error using try/catch:
try {
b()
} catch {
| Js.Exn.Error(error) => {
// error: Js.Exn.t
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
}
Or, catch the error using switch
and matching on the Js.Exn.Error
type:
switch b() {
| exception Js.Exn.Error(error) => {
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| () => ()
}
Or, catch the error using switch
, matching on any exception type, and detect the Js.Exn.t
type.
switch b() {
| exception error => {
// error: exn
let optError = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
// error: Js.Exn.t
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Unknown error")
}
}
| () => ()
}
Handling ReScript exceptions
Write a function that throws a custom ReScript exception:
exception MyException(string)
let c = (): unit => {
raise(MyException("An error occurred"))
}
Handle using try/catch, matching on the exception:
try {
c()
} catch {
| MyException(reason) => Js.log("MyException:" ++ reason)
}
Handle using switch
, matching on the exception.
Notice the need for the exception
keyword here.
switch c() {
| exception MyException(reason) => Js.log("MyException:" ++ reason)
| () => ()
}
Handle using switch
and try detect if it's a JavaScript error:
switch c() {
| exception error => {
// error: exn
let optError: option<Js.Exn.t> = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
// error: Js.Exn.t
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Not a JavaScript error")
}
}
| () => ()
}
This prints "Not a JavaScript error", as expected
Handling promise rejections from JavaScript
Write a JavaScript function that returns a rejected promise, and add a binding for it.
%%raw(`
function d() {
return Promise.reject(new Error("An error occurred"))
}
`)
@bs.val external d: unit => Js.Promise.t<unit> = "d"
Catch the error and attempt to identify that it's a JavaScript error.
d()->Js.Promise.catch((error: Js.Promise.error) => {
switch error {
| exception error => {
let optError: option<Js.Exn.t> = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Not a Js.Exn.t")
}
}
| _ => Js.log("Not an exn")
}
Js.Promise.resolve()
}, _)
This prints:
Not an exn
Notes:
- The JavaScript error is converted to type
Js.Promise.error
, which is not a member of theexn
type. - The switch case
exception error
match does not occur, because the error is not anexn
type.
Handling JavaScript promise rejections from ReScript
Write a function that returns a rejected promise containing a JavaScript error.
let e = (): Js.Promise.t<unit> => {
Js.Promise.make((~resolve as _, ~reject as _) => {
Js.Exn.raiseError("An error occurred")
})
}
Note: Raising the error has the effect of rejecting the promise.
Catch the error and try detect that it's a JavaScript error.
e()->Js.Promise.catch((error: Js.Promise.error) => {
switch error {
| exception error => {
let optError: option<Js.Exn.t> = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Not a Js.Exn.t")
}
}
| _ => Js.log("Not an exn")
}
Js.Promise.resolve()
}, _)
This prints:
Not an exn
Notes:
- The JavaScript error is converted to type
Js.Promise.error
, which is not a member of theexn
type. - The switch case
exception error
match does not occur, because the error is not anexn
type.
Handling ReScript promise rejections from ReScript
Write a function that returns a rejected promise containing a Rescript error.
exception MyException(string)
let f = (): Js.Promise.t<unit> => {
Js.Promise.make((~resolve as _, ~reject as _) => {
raise(MyException("An error occurred"))
})
}
Note: Raising the error has the effect of rejecting the promise.
Catch the error and attempt to determine its type:
f()->Js.Promise.catch((error: Js.Promise.error) => {
switch error {
| exception error => {
let optError: option<Js.Exn.t> = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Not a Js.Exn.t")
}
}
| _ => Js.log("Not an exn")
}
Js.Promise.resolve()
}, _)
This prints:
Not an exn
Notes:
- The ReScript error is converted to type
Js.Promise.error
, which is not a member of theexn
type. - The switch case
exception error
match does not occur, because the error is not anexn
type.
Handling ReScript promise rejections using the exn Failure variant.
The Failure(string)
variant has an exn
type.
Write a function that rejects a promise using a Failure
:
let g = (): Js.Promise.t<unit> => {
Js.Promise.make((~resolve as _, ~reject) => {
reject(. Failure("An error occurred"))
})
}
Catch the error and attempt to determine its type:
g()->Js.Promise.catch((error: Js.Promise.error) => {
switch error {
| exception error => {
let optError: option<Js.Exn.t> = Js.Exn.asJsExn(error)
switch optError {
| Some(error) => {
Js.log(Js.Exn.name(error))
Js.log(Js.Exn.message(error))
}
| None => Js.log("Not a Js.Exn.t")
}
}
| _ => Js.log("Not an exn")
}
Js.Promise.resolve()
}, _)
This prints:
Not an exn
Notes:
- The Failure error is converted to type
Js.Promise.error
, which is not a member of theexn
type. - The switch case
exception error
match does not occur, because the error is not anexn
type.
References
Posted on November 21, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.