This is the latest docs version
Quick Links
  • -Overview
  • -Language Features
  • -JS Interop
  • -Build System
Documentation
Language Manual
Reference for all language features
ReScript & React
First class bindings for ReactJS
GenType
Seamless TypeScript integration
Reanalyze
Dead Code & Termination analysis
Exploration
Packages
Explore third party libraries and bindings
Syntax Lookup
Discover all syntax constructs
APIPlaygroundBlogCommunity
  • Playground
  • Blog
  • Twitter
  • GitHub
  • Forum
Language Manual
Overview
  • Introduction
  • Installation
  • Migrate to v11
  • Editor Plugins
  • Try
Language Features
  • Overview
  • Let Binding
  • Type
  • Primitive Types
  • Tuple
  • Record
  • Object
  • Variant
  • Polymorphic Variant
  • Null, Undefined and Option
  • Array & List
  • Function
  • If-Else & Loops
  • Pipe
  • Pattern Matching / Destructuring
  • Mutation
  • JSX
  • Exception
    • Usage
    • Catching JS Exceptions
    • Raise a JS Exception
    • Catch ReScript Exceptions from JS
    • Tips & Tricks
  • Lazy Value
  • Promises
  • Async / Await
  • Tagged templates
  • Module
  • Import & Export
  • Attribute (Decorator)
  • Reserved Keywords
  • Equality and Comparison
Advanced Features
  • Extensible Variant
  • Scoped Polymorphic Types
JavaScript Interop
  • Interop Cheatsheet
  • Embed Raw JavaScript
  • Shared Data Types
  • External (Bind to Any JS Library)
  • Bind to JS Object
  • Bind to JS Function
  • Import from / Export to JS
  • Bind to Global JS Values
  • JSON
  • Inlining Constants
  • Use Illegal Identifier Names
  • Generate Converters & Helpers
  • Browser Support & Polyfills
  • Libraries & Publishing
  • TypeScript
Build System
  • Overview
  • Configuration
  • Configuration Schema
  • External Stdlib
  • Pinned Dependencies
  • Interop with JS Build Systems
  • Performance
  • Warning Numbers
Guides
  • Converting from JS
Extra
  • Newcomer Examples
  • Project Structure
  • FAQ
Docs / Language Manual / Exception
Edit

Exception

Exceptions are just a special kind of variant, thrown in exceptional cases (don't abuse them!).

Usage

ReScriptJS Output
let getItem = (item: int) =>
  if (item === 3) {
    // return the found item here
    1
  } else {
    raise(Not_found)
  }

let result =
  try {
    getItem(2)
  } catch {
  | Not_found => 0 // Default value if getItem throws
  }

Note that the above is just for demonstration purposes; in reality, you'd return an option<int> directly from getItem and avoid the try altogether.

You can directly match on exceptions while getting another return value from a function:

ReScriptJS Output
switch list{1, 2, 3}->List.getExn(4) {
| item => Console.log(item)
| exception Not_found => Console.log("No such item found!")
}

You can also make your own exceptions like you'd make a variant (exceptions need to be capitalized too).

ReScriptJS Output
exception InputClosed(string)
// later on
raise(InputClosed("The stream has closed!"))

Catching JS Exceptions

To distinguish between JavaScript exceptions and ReScript exceptions, ReScript namespaces JS exceptions under the Exn.Error(payload) variant. To catch an exception thrown from the JS side:

Throw an exception from JS:

JS
// Example.js exports.someJsFunctionThatThrows = () => { throw new Error("A Glitch in the Matrix!"); }

Then catch it from ReScript:

RES
// import the method in Example.js @module("./Example") external someJsFunctionThatThrows: () => unit = "someJsFunctionThatThrows" try { // call the external method someJSFunctionThatThrows() } catch { | Exn.Error(obj) => switch Exn.message(obj) { | Some(m) => Console.log("Caught a JS exception! Message: " ++ m) | None => () } }

The obj here is of type Exn.t, intentionally opaque to disallow illegal operations. To operate on obj, do like the code above by using the standard library's Exn module's helpers.

Raise a JS Exception

raise(MyException) raises a ReScript exception. To raise a JavaScript exception (whatever your purpose is), use Exn.raiseError:

ReScriptJS Output
let myTest = () => {
  Exn.raiseError("Hello!")
}

Then you can catch it from the JS side:

JS
// after importing `myTest`... try { myTest() } catch (e) { console.log(e.message) // "Hello!" }

Catch ReScript Exceptions from JS

The previous section is less useful than you think; to let your JS code work with your exception-throwing ReScript code, the latter doesn't actually need to throw a JS exception. ReScript exceptions can be used by JS code!

ReScriptJS Output
exception BadArgument({myMessage: string})

let myTest = () => {
  raise(BadArgument({myMessage: "Oops!"}))
}

Then, in your JS:

JS
// after importing `myTest`... try { myTest() } catch (e) { console.log(e.myMessage) // "Oops!" console.log(e.Error.stack) // the stack trace }

Note: RE_EXN_ID is an internal field for bookkeeping purposes. Don't use it on the JS side. Use the other fields.

The above BadArgument exception takes an inline record type. We special-case compile the exception as {RE_EXN_ID, myMessage, Error} for good ergonomics. If the exception instead took ordinary positional arguments, l like the standard library's Invalid_argument("Oops!"), which takes a single argument, the argument is compiled to JS as the field _1 instead. A second positional argument would compile to _2, etc.

Tips & Tricks

When you have ordinary variants, you often don't need exceptions. For example, instead of throwing when item can't be found in a collection, try to return an option<item> (None in this case) instead.

Catch Both ReScript and JS Exceptions in the Same catch Clause

RES
try { someOtherJSFunctionThatThrows() } catch { | Not_found => ... // catch a ReScript exception | Invalid_argument(_) => ... // catch a second ReScript exception | Exn.Error(obj) => ... // catch the JS exception }

This technically works, but hopefully you don't ever have to work with such code...

JSXLazy Value

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on