# Overview
## ReScript Core
[Core](api/core) is ReScript's new standard library. It replaces the complete `Js` module as well as some of the more frequently used modules from `Belt` and is recommended to use with uncurried mode.
In ReScript 11, it is shipped as a separate npm package `@rescript/core` that is added to your project as per the [installation instructions](/docs/manual/latest/installation). In future ReScript versions, it will be included with the `rescript` npm package itself.
## Additional Libraries
ReScript ships with these two additional modules in its standard library:
- [Belt](api/belt): immutable collections and extra helpers not available in JavaScript / [Core](api/core).
- [Dom](api/dom): Dom related types and modules. Contains our standardized types used by various userland DOM bindings.
## Legacy Modules
The [Js](api/js) module is superseded by [Core](api/core).
---
title: "Array & List"
description: "Arrays and List data structures"
canonical: "/docs/manual/v11.0.0/array-and-list"
---
# Array and List
## Array
Arrays are our main ordered data structure. They work the same way as JavaScript arrays: they can be randomly accessed, dynamically resized, updated, etc.
```res example
let myArray = ["hello", "world", "how are you"]
```
```js
var myArray = ["hello", "world", "how are you"];
```
ReScript arrays' items must have the same type, i.e. homogeneous.
### Usage
#### Access
Accessing items in an array will return an `option` and can be done like so:
```res example
let myArray = ["hello", "world", "how are you"]
let firstItem = myArray[0] // Some("hello")
let tenthItem = myArray->Array.get(10) // None
```
```js
var myArray = ["hello", "world", "how are you"];
var firstItem = myArray[0];
var tenthItem = myArray[10];
```
The behavior of returning an `option` is new to V11 when you have [Core](api/core) open.
It provides a safer way to access array items, which is especially useful when you're not sure if the index is out of bounds.
If you would like to not use an `option`, you can use [`Array.getUnsafe`](api/core/array#value-getUnsafe).
#### Update
Items in an array can be updated by assigning a value to an index or using a function:
```res example
let myArray = ["hello", "world", "how are you"]
myArray[0] = "hey" // now ["hey", "world", "how are you"]
myArray->Array.push("?") // ["hey", "world", "how are you", "?"]
myArray->Array.set(0, "bye") // ["bye", "world", "how are you", "?"]
```
```js
var myArray = ["hello", "world", "how are you"];
myArray[0] = "hey";
myArray.push("?");
myArray[0] = "bye";
```
### Array spreads
**Since 11.1**
You can spread arrays of the the same type into new arrays, just like in JavaScript:
```res example
let y = [1, 2]
let x = [4, 5, ...y]
let x2 = [4, 5, ...y, 7, ...y]
let x3 = [...y]
```
```javascript
var Belt_Array = require("rescript/lib/js/belt_Array.js");
var y = [
1,
2
];
var x = Belt_Array.concatMany([
[
4,
5
],
y
]);
var x2 = Belt_Array.concatMany([
[
4,
5
],
y,
[7],
y
]);
var x3 = Belt_Array.concatMany([y]);
```
> Note that array spreads compiles to `Belt.Array.concatMany` right now. This is likely to change to native array spreads in the future.
## List
ReScript provides a singly linked list too. Lists are:
- immutable
- fast at prepending items
- fast at getting the head
- slow at everything else
```res example
let myList = list{1, 2, 3}
```
```js
var myList = {
hd: 1,
tl: {
hd: 2,
tl: {
hd: 3,
tl: 0
}
}
};
```
Like arrays, lists' items need to be of the same type.
### Usage
You'd use list for its resizability, its fast prepend (adding at the head), and its fast split, all of which are immutable and relatively efficient.
Do **not** use list if you need to randomly access an item or insert at non-head position. Your code would end up obtuse and/or slow.
The standard lib provides a [List module](api/core/list).
#### Immutable Prepend
Use the spread syntax:
```res prelude
let myList = list{1, 2, 3}
let anotherList = list{0, ...myList}
```
```js
var myList = {
hd: 1,
tl: {
hd: 2,
tl: {
hd: 3,
tl: 0
}
}
};
var anotherList = {
hd: 0,
tl: myList
};
```
`myList` didn't mutate. `anotherList` is now `list{0, 1, 2, 3}`. This is efficient (constant time, not linear). `anotherList`'s last 3 elements are shared with `myList`!
**Note that `list{a, ...b, ...c}` was a syntax error** before compiler v10.1. In general, the pattern should be used with care as its performance and allocation overhead are linear (`O(n)`).
#### Access
`switch` (described in the [pattern matching section](pattern-matching-destructuring.md)) is usually used to access list items:
```res example
let message =
switch myList {
| list{} => "This list is empty"
| list{a, ...rest} => "The head of the list is the string " ++ Int.toString(a)
}
```
```js
var message = myList
? "The head of the list is the string " + (1).toString()
: "This list is empty";
```
---
title: "Async / Await"
description: "Async / await for asynchronous operations"
canonical: "/docs/manual/v11.0.0/async-await"
---
# Async / Await
ReScript comes with `async` / `await` support to make asynchronous, `Promise` based code easier to read and write. This feature is very similar to its JS equivalent, so if you are already familiar with JS' `async` / `await`, you will feel right at home.
## How it looks
Let's start with a quick example to show-case the syntax:
```res
// Some fictive functionality that offers asynchronous network actions
@val external fetchUserMail: string => promise = "GlobalAPI.fetchUserMail"
@val external sendAnalytics: string => promise = "GlobalAPI.sendAnalytics"
// We use the `async` keyword to allow the use of `await` in the function body
let logUserDetails = async (userId: string) => {
// We use `await` to fetch the user email from our fictive user endpoint
let email = await fetchUserMail(userId)
await sendAnalytics(`User details have been logged for ${userId}`)
Console.log(`Email address for user ${userId}: ${email}`)
}
```
```js
async function logUserDetails(userId) {
var email = await GlobalAPI.fetchUserMail(userId);
await GlobalAPI.sendAnalytics("User details have been logged for " + userId + "");
console.log("Email address for user " + userId + ": " + email + "");
}
```
As we can see above, an `async` function is defined via the `async` keyword right before the function's parameter list. In the function body, we are now able to use the `await` keyword to explicitly wait for a `Promise` value and assign its content to a let binding `email`.
You will probably notice that this looks very similar to `async` / `await` in JS, but there are still a few details that are specific to ReScript. The next few sections will go through all the details that are specific to the ReScript type system.
## Basics
- You may only use `await` in `async` function bodies
- `await` may only be called on a `promise` value
- `await` calls are expressions, therefore they can be used in pattern matching (`switch`)
- A function returning a `promise<'a>` is equivalent to an `async` function returning a value `'a` (important for writing signature files and bindings)
- `promise` values and types returned from an `async` function don't auto-collapse into a "flat promise" like in JS (more on this later)
## Types and `async` functions
### `async` function type signatures
Function type signatures (i.e defined in signature files) don't require any special keywords for `async` usage. Whenever you want to type an `async` function, use a `promise` return type.
```resi
// Demo.resi
let fetchUserMail: string => promise
```
The same logic applies to type definitions in `.res` files:
```res example
// function type
type someAsyncFn = int => promise
// Function type annotation
let fetchData: string => promise = async (userId) => {
await fetchUserMail(userId)
}
```
**BUT:** When typing `async` functions in your implementation files, you need to omit the `promise<'a>` type:
```res
// This function is compiled into a `string => promise` type.
// The promise<...> part is implicitly added by the compiler.
let fetchData = async (userId: string): string => {
await fetchUserMail("test")
}
```
For completeness reasons, let's expand the full signature and inline type definitions in one code snippet:
```res
// Note how the inline return type uses `string`, while the type definition uses `promise`
let fetchData: string => promise = async (userId: string): string {
await fetchUserMail(userId)
}
```
**Note:** In a practical scenario you'd either use a type signature, or inline types, not both at the same time. In case you are interested in the design decisions, check out [this discussion](https://github.com/rescript-lang/rescript/pull/5913#issuecomment-1359003870).
### Promises don't auto-collapse in async functions
In JS, nested promises (i.e. `promise>`) will automatically collapse into a flat promise (`promise<'a>`). This is not the case in ReScript. Use the `await` function to manually unwrap any nested promises within an `async` function instead.
```res
let fetchData = async (userId: string): string => {
// We can't just return the result of `fetchUserMail`, otherwise we'd get a
// type error due to our function return type of type `string`
await fetchUserMail(userId)
}
```
## Error handling
You may use `try / catch` or `switch` to handle exceptions during async execution.
```res
// For simulation purposes
let authenticate = async () => {
raise(Exn.raiseRangeError("Authentication failed."))
}
let checkAuth = async () => {
try {
await authenticate()
} catch {
| Exn.Error(e) =>
switch Exn.message(e) {
| Some(msg) => Console.log("JS error thrown: " ++ msg)
| None => Console.log("Some other exception has been thrown")
}
}
}
```
Note how we are essentially catching JS errors the same way as described in our [Exception](exception#catch-rescript-exceptions-from-js) section.
You may unify error and value handling in a single switch as well:
```res
let authenticate = async () => {
raise(Exn.raiseRangeError("Authentication failed."))
}
let checkAuth = async () => {
switch await authenticate() {
| _ => Console.log("ok")
| exception Exn.Error(e) =>
switch Exn.message(e) {
| Some(msg) => Console.log("JS error thrown: " ++ msg)
| None => Console.log("Some other exception has been thrown")
}
}
}
```
**Important:** When using `await` with a `switch`, always make sure to put the actual await call in the `switch` expression, otherwise your `await` error will not be caught.
## Piping `await` calls
You may want to pipe the result of an `await` call right into another function.
This can be done by wrapping your `await` calls in a new `{}` closure.
```res example
@val external fetchUserMail: string => promise = "GlobalAPI.fetchUserMail"
let fetchData = async () => {
let mail = {await fetchUserMail("1234")}->String.toUpperCase
Console.log(`All upper-cased mail: ${mail}`)
}
```
```js
async function fetchData(param) {
var mail = (await GlobalAPI.fetchUserMail("1234")).toUpperCase();
console.log("All upper-cased mail: " + mail + "");
}
```
Note how the original closure was removed in the final JS output. No extra allocations!
## Pattern matching on `await` calls
`await` calls are just another kind of expression, so you can use `switch` pattern matching for more complex logic.
```res example
@val external fetchUserMail: string => promise = "GlobalAPI.fetchUserMail"
let fetchData = async () => {
switch (await fetchUserMail("user1"), await fetchUserMail("user2")) {
| (user1Mail, user2Mail) => {
Console.log("user 1 mail: " ++ user1Mail)
Console.log("user 2 mail: " ++ user2Mail)
}
| exception JsError(err) => Console.log2("Some error occurred", err)
}
}
```
```js
async function fetchData(param) {
var val;
var val$1;
try {
val = await GlobalAPI.fetchUserMail("user1");
val$1 = await GlobalAPI.fetchUserMail("user2");
}
catch (raw_err){
var err = Caml_js_exceptions.internalToOCamlException(raw_err);
if (err.RE_EXN_ID === "JsError") {
console.log("Some error occurred", err._1);
return ;
}
throw err;
}
console.log("user 1 mail: " + val);
console.log("user 2 mail: " + val$1);
}
```
## `await` multiple promises
We can utilize the `Promise` module to handle multiple promises. E.g. let's use `Promise.all` to wait for multiple promises before continuing the program:
```res
let pauseReturn = (value, timeout) => {
Promise.make((resolve, _reject) => {
setTimeout(() => {
resolve(value)
}, timeout)->ignore
})
}
let logMultipleValues = async () => {
let promise1 = pauseReturn("value1", 2000)
let promise2 = pauseReturn("value2", 1200)
let promise3 = pauseReturn("value3", 500)
let all = await Promise.all([promise1, promise2, promise3])
switch all {
| [v1, v2, v3] => Console.log(`All values: ${v1}, ${v2}, ${v3}`)
| _ => Console.log("this should never happen")
}
}
```
## JS Interop with `async` functions
`async` / `await` practically works with any function that returns a `promise<'a>` value. Map your `promise` returning function via an `external`, and use it in an `async` function as usual.
Here's a full example of using the MDN `fetch` API, using `async` / `await` to simulate a login:
```res
// A generic Response type for typing our fetch requests
module Response = {
type t<'data>
@send external json: t<'data> => promise<'data> = "json"
}
// A binding to our globally available `fetch` function. `fetch` is a
// standardized function to retrieve data from the network that is available in
// all modern browsers.
@val @scope("globalThis")
external fetch: (
string,
'params,
) => promise, "error": Nullable.t}>> =
"fetch"
// We now use our asynchronous `fetch` function to simulate a login.
// Note how we use `await` with regular functions returning a `promise`.
let login = async (email: string, password: string) => {
let body = {
"email": email,
"password": password,
}
let params = {
"method": "POST",
"headers": {
"Content-Type": "application/json",
},
"body": Json.stringifyAny(body),
}
try {
let response = await fetch("https://reqres.in/api/login", params)
let data = await response->Response.json
switch Nullable.toOption(data["error"]) {
| Some(msg) => Error(msg)
| None =>
switch Nullable.toOption(data["token"]) {
| Some(token) => Ok(token)
| None => Error("Didn't return a token")
}
}
} catch {
| _ => Error("Unexpected network error occurred")
}
}
```
---
title: "Attribute (Decorator)"
description: "Annotations in ReScript"
canonical: "/docs/manual/v11.0.0/attribute"
---
# Attribute (Decorator)
Like many other languages, ReScript allows annotating a piece of code to express extra functionality. Here's an example:
```res
@inline
let mode = "dev"
let mode2 = mode
```
```js
var mode2 = "dev";
```
The `@inline` annotation tells `mode`'s value to be inlined into its usage sites (see output). We call such annotation "attribute" (or "decorator" in JavaScript).
An attribute starts with `@` and goes before the item it annotates. In the above example, it's hooked onto the let binding.
## Usage
> **Note:** In previous versions (< 8.3) all our interop related attributes started with a `bs.` prefix (`bs.module`, `bs.val`). Our formatter will automatically drop them in newer ReScript versions.
You can put an attribute almost anywhere. You can even add extra data to them by using them visually like a function call. Here are a few famous attributes (explained in other sections):
```res
@@warning("-27")
@unboxed
type a = Name(string)
@val external message: string = "message"
type student = {
age: int,
@as("aria-label") ariaLabel: string,
}
@deprecated
let customDouble = foo => foo * 2
@deprecated("Use SomeOther.customTriple instead")
let customTriple = foo => foo * 3
```
```js
```
1. `@@warning("-27")` is a standalone attribute that annotates the entire file. Those attributes start with `@@`. Here, it carries the data `"-27"`. You can find a full list of all available warnings [here](./warning-numbers).
2. `@unboxed` annotates the type definition.
3. `@val` annotates the `external` statement.
4. `@as("aria-label")` annotates the `ariaLabel` record field.
5. `@deprecated` annotates the `customDouble` expression. This shows a warning while compiling telling consumers to not rely on this method long-term.
6. `@deprecated("Use SomeOther.customTriple instead")` annotates the `customTriple` expression with a string to describe the reason for deprecation.
For a list of all decorators and their usage, please refer to the [Syntax Lookup](/syntax-lookup) page.
## Extension Point
There's a second category of attributes, called "extension points" (a remnant term of our early systems):
```res
%raw("var a = 1")
```
```js
var a = 1
```
Extension points are attributes that don't _annotate_ an item; they _are_ the item. Usually they serve as placeholders for the compiler to implicitly substitute them with another item.
Extension points start with `%`. A standalone extension point (akin to a standalone regular attribute) starts with `%%`.
For a list of all extension points and their usage, please refer to the [Syntax Lookup](/syntax-lookup) page.
---
title: "Bind to Global JS Values"
description: "JS interop with global JS values in ReScript"
canonical: "/docs/manual/v11.0.0/bind-to-global-js-values"
---
# Bind to Global JS Values
**First**, make sure the value you'd like to model doesn't already exist in our [provided API](api/core).
Some JS values, like `setTimeout`, live in the global scope. You can bind to them like so:
```res example
@val external setTimeout: (unit => unit, int) => float = "setTimeout"
@val external clearTimeout: float => unit = "clearTimeout"
```
```js
// Empty output
```
(We already provide `setTimeout`, `clearTimeout` and others in the [Core API](api/core) module).
This binds to the JavaScript [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrworkerGlobalScope/setTimeout) methods and the corresponding `clearTimeout`. The `external`'s type annotation specifies that `setTimeout`:
- Takes a function that accepts `unit` and returns `unit` (which on the JS side turns into a function that accepts nothing and returns nothing aka `undefined`),
- and an integer that specifies the duration before calling said function,
- returns a number that is the timeout's ID. This number might be big, so we're modeling it as a float rather than the 32-bit int.
### Tips & Tricks
**The above isn't ideal**. See how `setTimeout` returns a `float` and `clearTimeout` accepts one. There's no guarantee that you're passing the float created by `setTimeout` into `clearTimeout`! For all we know, someone might pass it `Math.random()` into the latter.
We're in a language with a great type system now! Let's leverage a popular feature to solve this problem: abstract types.
```res example
type timerId
@val external setTimeout: (unit => unit, int) => timerId = "setTimeout"
@val external clearTimeout: timerId => unit = "clearTimeout"
let id = setTimeout(() => Console.log("hello"), 100)
clearTimeout(id)
```
```js
var id = setTimeout(function (param) {
console.log("hello");
}, 100);
clearTimeout(id);
```
Clearly, `timerId` is a type that can only be created by `setTimeout`! Now we've guaranteed that `clearTimeout` _will_ be passed a valid ID. Whether it's a number under the hood is now a mere implementation detail.
Since `external`s are inlined, we end up with JS output as readable as hand-written JS.
## Global Modules
If you want to bind to a value inside a global module, e.g. `Math.random`, attach a `scope` to your `val` external:
```res example
@scope("Math") @val external random: unit => float = "random"
let someNumber = random()
```
```js
var someNumber = Math.random();
```
you can bind to an arbitrarily deep object by passing a tuple to `scope`:
```res example
@val @scope(("window", "location", "ancestorOrigins"))
external length: int = "length"
```
```js
// Empty output
```
This binds to `window.location.ancestorOrigins.length`.
## Special Global Values
Global values like `__filename` and `__DEV__` don't always exist; you can't even model them as an `option`, since the mere act of referring to them in ReScript (then compiled into JS) would trigger the usual `Uncaught ReferenceError: __filename is not defined` error in e.g. the browser environment.
For these troublesome global values, ReScript provides a special approach: `%external(a_single_identifier)`.
```res example
switch %external(__DEV__) {
| Some(_) => Console.log("dev mode")
| None => Console.log("production mode")
}
```
```js
var match = typeof __DEV__ === "undefined" ? undefined : __DEV__;
if (match !== undefined) {
console.log("dev mode");
} else {
console.log("production mode");
}
```
That first line's `typeof` check won't trigger a JS ReferenceError.
Another example:
```res example
switch %external(__filename) {
| Some(f) => Console.log(f)
| None => Console.log("non-node environment")
};
```
```js
var match = typeof (__filename) === "undefined" ? undefined : (__filename);
if (match !== undefined) {
console.log(match);
} else {
console.log("non-node environment");
}
```
---
title: "Bind to JS Function"
description: "JS interop with functions in ReScript"
canonical: "/docs/manual/v11.0.0/bind-to-js-function"
---
# Function
Binding a JS function is like binding any other value:
```res example
// Import nodejs' path.dirname
@module("path") external dirname: string => string = "dirname"
let root = dirname("/User/github") // returns "User"
```
```js
var Path = require("path");
var root = Path.dirname("/User/github");
```
We also expose a few special features, described below.
## Labeled Arguments
ReScript has [labeled arguments](function.md#labeled-arguments) (that can also be optional). These work on an `external` too! You'd use them to _fix_ a JS function's unclear usage. Assuming we're modeling this:
```js
// MyGame.js
function draw(x, y, border) {
// suppose `border` is optional and defaults to false
}
draw(10, 20)
draw(20, 20, true)
```
It'd be nice if on ReScript's side, we can bind & call `draw` while labeling things a bit:
```res example
@module("MyGame")
external draw: (~x: int, ~y: int, ~border: bool=?) => unit = "draw"
draw(~x=10, ~y=20, ~border=true)
draw(~x=10, ~y=20)
```
```js
var MyGame = require("MyGame");
MyGame.draw(10, 20, true);
MyGame.draw(10, 20, undefined);
```
We've compiled to the same function, but now the usage is much clearer on the ReScript side thanks to labels!
Note that you can freely reorder the labels on the ReScript side; they'll always correctly appear in their declaration order in the JavaScript output:
```res example
@module("MyGame")
external draw: (~x: int, ~y: int, ~border: bool=?) => unit = "draw"
draw(~x=10, ~y=20)
draw(~y=20, ~x=10)
```
```js
var MyGame = require("MyGame");
MyGame.draw(10, 20, undefined);
MyGame.draw(10, 20, undefined);
```
## Object Method
Functions attached to a JS objects (other than JS modules) require a special way of binding to them, using `send`:
```res example
type document // abstract type for a document object
@send external getElementById: (document, string) => Dom.element = "getElementById"
@val external doc: document = "document"
let el = getElementById(doc, "myId")
```
```js
var el = document.getElementById("myId");
```
In a `send`, the object is always the first argument. Actual arguments of the method follow (this is a bit what modern OOP objects are really).
### Chaining
Ever used `foo().bar().baz()` chaining ("fluent api") in JS OOP? We can model that in ReScript too, through the [pipe operator](pipe.md).
### Nested function call
`@send` can also accept a `@scope(("itemOne","itemTwo"))` to access a function on a nested property.
```res example
type stripe
@module("stripe") @new
external make: string => stripe = "default"
type createSession = {}
type sessionResult
@send
@scope(("checkout", "sessions"))
external createCheckoutSession: (stripe, createSession) =>
Promise.t = "create"
let stripe = make("sk_...")
let session = stripe->createCheckoutSession({})
```
```js
import Stripe from "stripe";
var stripe = new Stripe("sk_...");
var session = stripe.checkout.sessions.create({});
```
## Variadic Function Arguments
You might have JS functions that take an arbitrary amount of arguments. ReScript supports modeling those, under the condition that the arbitrary arguments part is homogenous (aka of the same type). If so, add `variadic` to your `external`.
```res example
@module("path") @variadic
external join: array => string = "join"
let v = join(["a", "b"])
```
```js
var Path = require("path");
var v = Path.join("a", "b");
```
`module` will be explained in [Import from/Export to JS](import-from-export-to-js.md).
## Modeling Polymorphic Function
Apart from the above special-case, JS functions in general are often arbitrarily overloaded in terms of argument types and number. How would you bind to those?
### Trick 1: Multiple `external`s
If you can exhaustively enumerate the many forms an overloaded JS function can take, simply bind to each differently:
```res example
@module("MyGame") external drawCat: unit => unit = "draw"
@module("MyGame") external drawDog: (~giveName: string) => unit = "draw"
@module("MyGame") external draw: (string, ~useRandomAnimal: bool) => unit = "draw"
```
```js
// Empty output
```
Note how all three externals bind to the same JS function, `draw`.
### Trick 2: Polymorphic Variant + `unwrap`
If you have the irresistible urge of saying "if only this JS function argument was a variant instead of informally being either `string` or `int`", then good news: we do provide such `external` features through annotating a parameter as a polymorphic variant! Assuming you have the following JS function you'd like to bind to:
```js
function padLeft(value, padding) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
```
Here, `padding` is really conceptually a variant. Let's model it as such.
```res example
@val
external padLeft: (
string,
@unwrap [
| #Str(string)
| #Int(int)
])
=> string = "padLeft"
padLeft("Hello World", #Int(4))
padLeft("Hello World", #Str("Message from ReScript: "))
```
```js
padLeft("Hello World", 4);
padLeft("Hello World", "Message from ReScript: ");
```
Obviously, the JS side couldn't have an argument that's a polymorphic variant! But here, we're just piggy backing on poly variants' type checking and syntax. The secret is the `@unwrap` annotation on the type. It strips the variant constructors and compile to just the payload's value. See the output.
## Constrain Arguments Better
Consider the Node `fs.readFileSync`'s second argument. It can take a string, but really only a defined set: `"ascii"`, `"utf8"`, etc. You can still bind it as a string, but we can use poly variants + `string` to ensure that our usage's more correct:
```res example
@module("fs")
external readFileSync: (
~name: string,
@string [
| #utf8
| @as("ascii") #useAscii
],
) => string = "readFileSync"
readFileSync(~name="xx.txt", #useAscii)
```
```js
var Fs = require("fs");
Fs.readFileSync("xx.txt", "ascii");
```
- Attaching `@string` to the whole poly variant type makes its constructor compile to a string of the same name.
- Attaching a `@as("bla")` to a constructor lets you customize the final string.
And now, passing something like `"myOwnUnicode"` or other variant constructor names to `readFileSync` would correctly error.
Aside from string, you can also compile an argument to an int, using `int` instead of `string` in a similar way:
```res example
@val
external testIntType: (
@int [
| #onClosed
| @as(20) #onOpen
| #inBinary
])
=> int = "testIntType"
testIntType(#inBinary)
```
```js
testIntType(21);
```
`onClosed` compiles to `0`, `onOpen` to `20` and `inBinary` to **`21`**.
## Unknown for type safety
It is best practice to inspect data received from untrusted external functions to ensure it contains what you expect. This helps avoid run-time crashes and unexpected behavior. If you're certain about what an external function returns, simply assert the return value as `string` or `array` or whatever you want it to be. Otherwise use `unknown`. The ReScript type system will prevent you from using an `unknown` until you first inspect it and "convert" it using JSON parsing utilities or similar tools.
Consider the example below of two external functions that access the value of a property on a JavaScript object. `getPropertyUnsafe` returns an `'a`, which means "anything you want it to be." ReScript allows you to use this value as a `string` or `array` or any other type. Quite convenient! But if the property is missing or contains something unexpected, your code might break. You can make the binding more safe by changing `'a` to `string` or `option<'a>`, but this doesn't completely eliminate the problem.
The `getPropertySafe` function returns an `unknown`, which could be `null` or a `string` or anything else. But ReScript prevents you from using this value inappropriately until it has been safely parsed.
```res example
@get_index external getPropertyUnsafe: ({..}, string) => 'a = ""
@get_index external getPropertySafe: ({..}, string) => unknown = ""
let person = {"name": "Bob", "age": 12}
let greeting1 = "Hello, " ++ getPropertyUnsafe(person, "name") // works (this time!)
// let greeting2 = "Hello, " ++ getPropertySafe(person, "name") // syntax error
```
## Special-case: Event Listeners
One last trick with polymorphic variants:
```res example
type readline
@send
external on: (
readline,
@string [
| #close(unit => unit)
| #line(string => unit)
]
)
=> readline = "on"
let register = rl =>
rl
->on(#close(event => ()))
->on(#line(line => Console.log(line)));
```
```js
function register(rl) {
return rl
.on("close", function($$event) {})
.on("line", function(line) {
console.log(line);
});
}
```
## Fixed Arguments
Sometimes it's convenient to bind to a function using an `external`, while passing predetermined argument values to the JS function:
```res example
@val
external processOnExit: (
@as("exit") _,
int => unit
) => unit = "process.on"
processOnExit(exitCode =>
Console.log("error code: " ++ Int.toString(exitCode))
);
```
```js
process.on("exit", function (exitCode) {
console.log("error code: " + exitCode.toString());
});
```
The `@as("exit")` and the placeholder `_` argument together indicates that you want the first argument to compile to the string `"exit"`. You can also use any JSON literal with `as`: `` @as(json`true`) ``, `` @as(json`{"name": "John"}`) ``, etc.
## Ignore arguments
You can also explicitly "hide" `external` function parameters in the JS output, which may be useful if you want to add type constraints to other parameters without impacting the JS side:
```res
@val external doSomething: (@ignore 'a, 'a) => unit = "doSomething"
doSomething("this only shows up in ReScript code", "test")
```
```js
doSomething("test");
```
**Note:** It's a pretty niche feature, mostly used to map to polymorphic JS APIs.
## Modeling `this`-based Callbacks
Many JS libraries have callbacks which rely on this (the source), for example:
```js
x.onload = function(v) {
console.log(this.response + v)
}
```
Here, `this` would point to `x` (actually, it depends on how `onload` is called, but we digress). It's not correct to declare `x.onload` of type `(. unit) -> unit`. Instead, we introduced a special attribute, `this`, which allows us to type `x` as so:
```res example
type x
@val external x: x = "x"
@set external setOnload: (x, @this ((x, int) => unit)) => unit = "onload"
@get external resp: x => int = "response"
setOnload(x, @this (o, v) => Console.log(resp(o) + v))
```
```js
x.onload = function (v) {
var o = this;
console.log((o.response + v) | 0);
};
```
`@this` reserves the first parameter for the `this` value, and for arity of 0, there is no need for a redundant `unit` type.
## Function Nullable Return Value Wrapping
For JS functions that return a value that can also be `undefined` or `null`, we provide `@return(...)`. To automatically convert that value to an `option` type (recall that ReScript `option` type's `None` value only compiles to `undefined` and not `null`).
```res example
type element
type dom
@send @return(nullable)
external getElementById: (dom, string) => option = "getElementById"
let test = dom => {
let elem = dom->(getElementById("haha"))
switch (elem) {
| None => 1
| Some(_ui) => 2
}
}
```
```js
function test(dom) {
var elem = dom.getElementById("haha");
if (elem == null) {
return 1;
} else {
console.log(elem);
return 2;
}
}
```
`return(nullable)` attribute will automatically convert `null` and `undefined` to `option` type.
Currently 4 directives are supported: `null_to_opt`, `undefined_to_opt`, `nullable` and `identity`.
`identity` will make sure that compiler will do nothing about the returned value. It is rarely used, but introduced here for debugging purpose.
## Tagged template functions
**Since 11.1**
**Experimental** You can easily bind to [JS tagged template functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates).
Tag functions in JS expect as input an array of strings and variadic parameters for the arguments of the interpolation.
To bind to those functions in ReScript, the binding signature must have two arrays as arguments,
the first one being an array of strings and the second can be an array of anything.
You add the `@taggedTemplate` annotation and you're good to go!
```res example
// see https://bun.sh/docs/runtime/shell
type result = {exitCode: int}
@module("bun") @taggedTemplate
external sh: (array, array) => promise = "$"
let filename = "index.res"
let result = await sh`ls ${filename}`
```
```js
import * as $$Bun from "bun";
var filename = "index.res";
var result = await $$Bun.$`ls ${filename}`;
```
Notice that it gets compiled to tagged template literals in JS, which allows
to use JS tools that only work on the literals and not by calling directly the tag function.
There are plenty of useful JS tools you can bind to, like [`gql`](https://github.com/apollographql/graphql-tag),
[`sql`](https://github.com/porsager/postgres), [`css`](https://github.com/mayank99/ecsstatic) and a lot others!
---
title: "Bind to JS Object"
description: "Interop with JS objects in ReScript"
canonical: "/docs/manual/v11.0.0/bind-to-js-object"
---
# Bind to JS Object
JavaScript objects are a combination of several use-cases:
- As a "record" or "struct" in other languages (like ReScript and C).
- As a hash map.
- As a class.
- As a module to import/export.
ReScript cleanly separates the binding methods for JS object based on these 4 use-cases. This page documents the first three. Binding to JS module objects is described in the [Import from/Export to JS](import-from-export-to-js.md) section.
## Bind to Record-like JS Objects
### Bind Using ReScript Record
If your JavaScript object has fixed fields, then it's conceptually like a ReScript record. Since a ReScript record compiles to a clean JavaScript object, you can definitely type a JS object as a ReScript record!
```res example
type person = {
name: string,
friends: array,
age: int,
}
@module("MySchool") external john: person = "john"
let johnName = john.name
```
```js
var MySchool = require("MySchool");
var johnName = MySchool.john.name;
```
External is documented [here](external.md). `@module` is documented [here](import-from-export-to-js.md).
If you want or need to use different field names on the ReScript and the JavaScript side, you can use the `@as` decorator:
```res example
type action = {
@as("type") type_: string
}
let action = {type_: "ADD_USER"}
```
```js
var action = {
type: "ADD_USER"
};
```
This is useful to map to JavaScript attribute names that cannot be expressed in ReScript (such as keywords).
It is also possible to map a ReScript record to a JavaScript array by passing indices to the `@as` decorator:
```res
type t = {
@as("0") foo: int,
@as("1") bar: string,
}
let value = {foo: 7, bar: "baz"}
```
```js
var value = [
7,
"baz"
];
```
### Bind Using ReScript Object
Alternatively, you can use [ReScript object](object.md) to model a JS object too:
```res example
type person = {
"name": string,
"friends": array,
"age": int,
}
@module("MySchool") external john: person = "john"
let johnName = john["name"]
```
```js
var MySchool = require("MySchool");
var johnName = MySchool.john.name;
```
### Bind Using Special Getter and Setter Attributes
Alternatively, you can use `get` and `set` to bind to individual fields of a JS object:
```res example
type textarea
@set external setName: (textarea, string) => unit = "name"
@get external getName: textarea => string = "name"
```
```js
```
You can also use `get_index` and `set_index` to access a dynamic property or an index:
```res example
type t
@new external create: int => t = "Int32Array"
@get_index external get: (t, int) => int = ""
@set_index external set: (t, int, int) => unit = ""
let i32arr = create(3)
i32arr->set(0, 42)
Console.log(i32arr->get(0))
```
```js
var i32arr = new Int32Array(3);
i32arr[0] = 42;
console.log(i32arr[0]);
```
## Bind to Hash Map-like JS Object
If your JavaScript object:
- might or might not add/remove keys
- contains only values that are of the same type
Then it's not really an object, it's a hash map. Use [Dict](api/core/dict), which contains operations like `get`, `set`, etc. and cleanly compiles to a JavaScript object still.
## Bind to a JS Object That's a Class
Use `new` to emulate e.g. `new Date()`:
```res example
type t
@new external createDate: unit => t = "Date"
let date = createDate()
```
```js
var date = new Date();
```
You can chain `new` and `module` if the JS module you're importing is itself a class:
```res example
type t
@new @module external book: unit => t = "Book"
let myBook = book()
```
```js
var Book = require("Book");
var myBook = new Book();
```
---
title: "Browser Support & Polyfills"
description: "Note on browser support in ReScript"
canonical: "/docs/manual/v11.0.0/browser-support-polyfills"
---
# Browser Support & Polyfills
ReScript compiles to JavaScript **ES5**, with the exception of optionally allowing to compile to ES6's module import & export.
For [old browsers](https://caniuse.com/#search=typed%20array), you also need to polyfill TypedArray. The following standard library functions require it:
- `Int64.float_of_bits`
- `Int64.bits_of_float`
- `Int32.float_of_bits`
- `Int32.bits_of_float`
If you don't use these functions, you're fine. Otherwise, it'll be a runtime failure.
---
title: "Configuration Schema"
metaTitle: "Build System Configuration Schema"
description: "Schema exploration widget for the ReScript configuration file"
canonical: "/docs/manual/v11.0.0/build-configuration-schema"
---
import dynamic from "next/dynamic";
export const Docson = dynamic(
() =>
import("src/components/Docson").then((comp) => {
return comp.make;
}),
{
ssr: false,
loading: () =>
Loading...
,
}
);
export default function BuildConfigurationSchemaPage() {
return ;
}
---
title: "Configuration"
metaTitle: "Build System Configuration"
description: "Details about the configuration of the ReScript build system (rescript.json)"
canonical: "/docs/manual/v11.0.0/build-configuration"
---
# Configuration
`rescript.json` (or `bsconfig.json` in versions prior ReScript 11) is the single, mandatory build meta file needed for `rescript`.
**The complete configuration schema is [here](./build-configuration-schema)**. We'll _non-exhaustively_ highlight the important parts in prose below.
## name, namespace
`name` is the name of the library, used as its "namespace". You can activate namespacing through `"namespace": true` in your `rescript.json`. Namespacing is almost **mandatory**; we haven't turned it on by default yet to preserve backward-compatibility.
**Explanation**: by default, your files, once used as a third-party dependency, are available globally to the consumer. E.g. if you have a `Util.res` and the consumer also has a file of the same name, they will clash. Turning on `namespace` avoids this by wrapping all your own project's files into an extra module layer; instead of a global `Util` module, the consumer will see you as `MyProject.Util`. **The namespacing affects your consumers, not yourself**.
Aka, in ReScript, "namespace" is just a fancy term for an auto-generated module that wraps all your project's files (efficiently and correctly, of course!) for third-party consumption.
We don't do folder-level namespacing for your own project; all your own file names must be unique. This is a constraint that enables several features such as fast search and easier project reorganization.
**Note**: the `rescript.json` `name` should be the same as the `package.json` `name`, to avoid confusing corner-cases. However, this means that you can't use a camelCased names such as `MyProject`, since `package.json` and npm forbid you to do so (some file systems are case-insensitive). To have the namespace/module as `MyProject`, write `"name": "my-project"`. ReScript will turn that into the camelCased name correctly.
**Note on custom namespacing**: if for some reason, you need a namespace that is different from what your `name` will produce, you can directly send a string to the `namespace` option. For example, if your package is a binding named `bs-some-thing`, you can use `"namespace": "some-thing"` to get `SomeThing` namespace instead of `BsSomeThing`.
## sources
Your source files need to be specified explicitly (we don't want to accidentally drill down into some unrelated directories). Examples:
```json
{
"sources": ["src", "examples"]
}
```
```json
{
"sources": {
"dir": "src",
"subdirs": ["page"]
}
}
```
```json
{
"sources": [
"examples",
{
"dir": "src",
"subdirs": true // recursively builds every subdirectory
}
]
}
```
You can mark your directories as dev-only (for e.g. tests). These won't be built and exposed to third-parties, or even to other "dev" directories in the same project:
```json
{
"sources": {
"dir": "test",
"type": "dev"
}
}
```
You can also explicitly allow which modules can be seen from outside. This feature is especially useful for library authors who want to have a single entry point for their users.
Here, the file `src/MyMainModule.res` is exposed to outside consumers, while all other files are private.
```json
{
"sources": {
"dir": "src",
"public": ["MyMainModule"]
}
}
```
## bs-dependencies, bs-dev-dependencies
List of ReScript dependencies. Just like `package.json`'s dependencies, they'll be searched in `node_modules`.
Note that only sources marked with `"type":"dev"` will be able to resolve modules from `bs-dev-dependencies`.
## pinned-dependencies
**Since 8.4**: List of pinned dependencies. A pinned dependency will always be rebuilt whenever you build a toplevel package (e.g. your main app) with `rescript`.
This is useful for working on multiple independent ReScript packages simultaneously. More usage details can be found in our dedicated [pinned dependencies](./build-pinned-dependencies) page.
## external-stdlib
**Since 9.0**: This setting allows depending on an externally built stdlib package (instead of a locally built stdlib runtime). Useful for shipping packages that are only consumed in JS or TS without any dependencies to the ReScript development toolchain.
More details can be found on our [external stdlib](./build-external-stdlib) page.
## js-post-build
Hook that's invoked every time a file is recompiled. Good for JS build system interop, but please use it **sparingly**. Calling your custom command for every recompiled file slows down your build and worsens the building experience for even third-party users of your lib.
Example:
```json
{
"js-post-build": {
"cmd": "/path/to/node ../../postProcessTheFile.js"
}
}
```
Note that the path resolution for the command (`node` in this case) is done so:
- `/myCommand` is resolved into `/myCommand`
- `package/myCommand` is resolved into `node_modules/package/myCommand`
- `./myCommand` is resolved into `myProjectRoot/myCommand`
- `myCommand` is just called as `myCommand`, aka a globally available executable. But note that ReScript doesn't read into your shell's environment, so if you put e.g. `node`, it won't find it unless you specify an absolute path. Alternatively, add `#!/usr/local/bin/node` to the top of your script to directly call it without prepending `node`.
The command itself is called from inside `lib/bs`.
## package-specs
Output to either CommonJS (the default) or JavaScript module. Example:
```json
{
"package-specs": {
"module": "commonjs",
"in-source": true
}
}
```
- `"module": "commonjs"` generates output as CommonJS format.
- `"module": "esmodule"` generates output as JavaScript module format. Will be default value in next major.
- `"in-source": true` generates output alongside source files. If you omit it, it'll generate the artifacts into `lib/js`. The output directory is not configurable otherwise.
This configuration only applies to you, when you develop the project. When the project is used as a third-party library, the consumer's own `rescript.json` `package-specs` overrides the configuration here, logically.
## suffix
**Since 11.0**: The suffix can now be freely chosen. However, we still suggest you stick to the convention and use
one of the following:
- `".js`
- `".mjs"`
- `".cjs"`
- `".res.js"`
- `".res.mjs"`
- `".res.cjs"`
### Design Decisions
Generating JS files with the `.res.js` suffix means that, on the JS side, you can do `const myReScriptFile = require('./TheFile.res.js')`. The benefits:
- It's immediately clear that we're dealing with a generated JS file here.
- It avoids clashes with a potential `TheFile.js` file in the same folder.
- It avoids the need of using a build system loader for ReScript files. This + in-source build means integrating a ReScript project into your pure JS codebase **basically doesn't touch anything in your build pipeline at all**.
## uncurried
**Since 11.0**: While we strongly encourage all users to use uncurried mode, it is still possible to opt out. Just set `"uncurried"` to `false` to get the old behavior back:
```json
{
"uncurried": false
}
```
More details can be found in the [blogpost about "Uncurried Mode"](/blog/uncurried-mode).
## warnings
Selectively turn on/off certain warnings and/or turn them into hard errors. Example:
```json
{
"warnings": {
"number": "-44-102",
"error": "+5"
}
}
```
Turn off warning `44` and `102` (polymorphic comparison). Turn warning `5` (partial application whose result has function type and is ignored) into a hard error.
The warning numbers are shown in the build output when they're triggered. See [Warning Numbers](./warning-numbers) for the complete list.
## bsc-flags
Extra flags to pass to the compiler. For advanced usages.
- `-open ABC` opens the module `ABC` for each file in the project. `ABC` can either be a dependency, namespaced project or local module of the current project.
## gentypeconfig
To enable genType, set `"gentypeconfig"` at top level in the project's `rescript.json`.
```json
{
"gentypeconfig": {
"module": "esmodule",
"moduleResolution": "node",
"generatedFileExtension": ".gen.tsx",
"debug": {
"all": false,
"basic": false
}
}
}
```
`generatedFileExtension`: File extension used for genType generated files (defaults to `".gen.tsx"`)
`module`: Module format used for the generated `*.gen.tsx` files (supports `"esmodule"` and `"commonjs"`)
`moduleResolution`: Module resolution strategy used in genType outputs. This may be required for compatibility with TypeScript projects. Specify the value as the same in `tsconfig.json`.
- `"node"`(default): Drop extensions in import paths.
- `"node16"`: Use TS output's extension. This provides compatibility with projects using `"moduleResolution": "node16"` and ES Modules.
- `"bundler"`: Use TS input's extension. This provides compatibility with projects using `"moduleResolution": "bundler"` and ES Modules. This also requires TS v5.0+ and `compilerOptions.allowImportingTsExtensions` to `true`
`debug`: Enable debug logs.
### Deprecated options
`language`: the `language` setting is not required from compiler v10.1.
`shims`: Required only if one needs to export certain basic ReScript data types to JS when one cannot modify the sources to add annotations (e.g. exporting ReScript lists), and if the types are not first-classed in genType.
## Environment Variables
We heavily disrecommend the usage of environment variables, but for certain cases, they're justified.
### Error Output Coloring: `NINJA_ANSI_FORCED`
This is mostly for other programmatic usage of `rescript` where outputting colors is not desired.
When `NINJA_ANSI_FORCED` is set to `1`: `rescript` produces color.
When `NINJA_ANSI_FORCED` is set to `0`: `rescript` doesn't produce color.
When `NINJA_ANSI_FORCED` is not set: `rescript` might or might not produce color, depending on a smart detection of where it's outputted.
> Note that the underlying compiler will always be passed `-color always`. See more details in [this issue](https://github.com/rescript-lang/rescript/issues/2984#issuecomment-410669163).
---
title: "External Stdlib"
metaTitle: "External Stdlib"
description: "Configuring an external ReScript stdlib package"
canonical: "/docs/manual/v11.0.0/build-external-stdlib"
---
# External Stdlib
**Since 9.0**
Your ReScript project depends on the `rescript` package as a [`devDependency`](https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file), which includes our compiler, build system and runtime like `Belt`. However, you had to move it to `dependency` in `package.json` if you publish your code:
- To Docker or other low-storage deployment devices.
- For pure JS/TS consumers who probably won't install `rescript` in their own project.
In these cases, the size or mere presence of `rescript` can be troublesome, since it includes not just our necessary runtime like `Belt`, but also our compiler and build system.
To solve that, we now publish our runtime as a standalone package at [`@rescript/std`](https://www.npmjs.com/package/@rescript/std), whose versions mirror `rescript`'s. Now you can keep `rescript` as a `devDependency` and have only `@rescript/std` as your runtime `dependency`.
**This is an advanced feature**. Please only use it in the aforementioned scenarios. If you already use a JS bundler with dead code elimination, you might not need this feature.
## Configuration
Say you want to publish a JS-only ReScript 9.0 library. Install the packages like this:
```sh
npm install rescript@11.0.1 --save-dev
npm install @rescript/std@11.0.1
```
Then add this to `rescript.json`:
```json
{
// ...
"external-stdlib" : "@rescript/std"
}
```
Now the compiled JS code will import using the path defined by `external-stdlib`. Check the JS output tab:
```res
Array.forEach([1, 2, 3], num => Console.log(num))
```
```js
// Note the require path starting with "@rescript/std".
var Belt_Array = require("@rescript/std/lib/js/belt_Array.js");
Belt_Array.forEach([1, 2, 3], function (num) {
console.log(num);
});
```
**Make sure the version number of `rescript` and `@rescript/std` match in your `package.json`** to avoid running into runtime issues due to mismatching stdlib assumptions.
---
title: "Overview"
metaTitle: "Build System Overview"
description: "Documentation about the ReScript build system and its toolchain"
canonical: "/docs/manual/v11.0.0/build-overview"
---
# Build System Overview
ReScript comes with a build system, [`rescript`](https://www.npmjs.com/package/rescript), that's fast, lean and used as the authoritative build system of the community.
Every ReScript project needs a build description file, `rescript.json`.
## Options
See `rescript help`:
```
❯ rescript help
Usage: rescript
`rescript` is equivalent to `rescript build`
Options:
-v, -version display version number
-h, -help display help
Subcommands:
build
clean
format
convert
dump
help
Run `rescript -h` for subcommand help. Examples:
rescript build -h
rescript format -h
```
## Build Project
Each build will create build artifacts from your project's source files.
**To build a project (including its dependencies / pinned-dependencies)**, run:
```sh
rescript
```
Which is an alias for `rescript build`.
To keep a build watcher, run:
```sh
rescript -w
```
Any new file change will be picked up and the build will re-run.
**Note**: third-party libraries (in `node_modules`, or via `pinned-dependencies`) aren't watched, as doing so may exceed the node.js watcher count limit.
**Note 2**: In case you want to set up a project in a JS-monorepo-esque approach (`npm` and `yarn` workspaces) where changes in your sub packages should be noticed by the build, you will need to define pinned dependencies in your main project's `rescript.json`. More details [here](./build-pinned-dependencies).
## Clean Project
If you ever get into a stale build for edge-case reasons, use:
```sh
rescript clean
```
## Compile with stricter errors in CI
**Since 11.1**
You may want to compile your project with stricter rules for production, than when developing. With the `-warn-error` build flag, this can easily be done, for instance in a continuous integration script. E.g.:
```sh
rescript -warn-error +110
```
Here, warning number 110, which is triggered when a [`%todo`](/syntax-lookup#todo) has been found, gets promoted to an error. The full list of warning numbers can be found [here](/docs/manual/latest/warning-numbers).
---
title: "Performance"
metaTitle: "Build Performance"
description: "ReScript build performance and measuring tools"
canonical: "/docs/manual/v11.0.0/build-performance"
---
# Build Performance
ReScript considers performance at install time, build time and run time as a serious feature; it's one of those things you don't notice until you realize it's missing.
## Profile Your Build
Sometime your build can be slow due to some confused infra setups. We provide an interactive visualization of your build's performance via `bstracing`:
```sh
./node_modules/.bin/bstracing
```
Run the above command at your ReScript project's root; it'll spit out a JSON file you can drag and drop into `chrome://tracing`.
import Image from "src/components/Image";
## Under the Hood
ReScript itself uses a build system under the hood, called [Ninja](https://ninja-build.org). Ninja is like Make, but cross-platform, minimal, focuses on perf and destined to be more of a low-level building block than a full-blown build system. In this regard, Ninja's a great implementation detail for `rescript`.
ReScript reads into `rescript.json` and generates the Ninja build file in `lib/bs`. The file contains the low-level compiler commands, namespacing rules, intermediate artifacts generation & others. It then runs `ninja` for the actual build.
## The JS Wrapper
`rescript` itself is a Node.js wrapper which takes care of some miscellaneous tasks, plus the watcher. The lower-level, watcher-less, fast native `rescript` is called `rescript.exe`. It's located at `node_modules/rescript/{your-platform}/rescript.exe`.
If you don't need the watcher, you can run said `rescript.exe`. This side-steps Node.js' long startup time, which can be in the order of `100ms`. Our editor plugin finds and uses this native `rescript.exe` for better performance.
## Numbers
Raw `rescript.exe` build on a small project should be around `70ms`. This doubles when you use the JS `rescript` wrapper which comes with a watcher, which is practically faster since you don't manually run the build at every change (though you should opt for the raw `rescript.exe` for programmatic usage, e.g. inserting rescript into your existing JS build pipeline).
No-op build (when no file's changed) should be around `15ms`. Incremental rebuild (described soon) of a single file in a project is around `70ms` too.
Cleaning the artifacts should be instantaneous.
### Extreme Test
We've stress-tested `rescript.exe` on a big project of 10,000 files (2 directories, 5000 files each, first 5000 no dependencies, last 5000 10 dependencies on files from the former directory) using https://github.com/rescript-lang/build-benchmark, on a Retina Macbook Pro Early 2015 (3.1 GHz Intel Core i7).
- No-op build of 10k files: `800ms` (the minimum amount of time required to check the mtimes of 10k files).
- Clean build: \<3 minutes.
- Incremental build: depends on the number of the dependents of the file. No dependent means `1s`.
### Stability
`rescript` is a file-based build system. We don't do in-memory build, even if that speeds up the build a lot. In-memory builds risk memory leaks, out-of-memory errors, corrupt halfway build and others. Our watcher mode stays open for days or months with no leak.
The watcher is also just a thin file watcher that calls `rescript.exe`. We don't like babysitting daemon processes.
## Incrementality & Correctness
ReScript doesn't take whole seconds to run every time. The bulk of the build performance comes from incremental build, aka re-building a previously built project when a few files changed.
In short, thanks to our compiler and the build system's architecture, we're able to **only build what's needed**. E.g. if `MyFile.res` isn't changed, then it's not recompiled. You can roughly emulate such incrementalism in languages like JavaScript, but the degree of correctness is unfortunately low. For example, if you rename or move a JS file, then the watcher might get confused and not pick up the "new" file or fail to clean things up correctly, resulting in you needing to clean your build and restart anew, which defeats the purpose.
Say goodbye to stale build from your JavaScript ecosystem!
## Speed Up Incremental Build
ReScript uses the concept of interface files (`.resi`) (or, equivalently, [module signatures](module.md#signatures)). Exposing only what you need naturally speeds up incremental builds. E.g. if you change a `.res` file whose corresponding `.resi` file doesn't expose the changed part, then you've reduced the amount of dependent files you have to rebuild.
## Programmatic Usage
Unfortunately, JS build systems are usually the bottleneck for building a JS project nowadays. Having parts of the build blazingly fast doesn't matter much if the rest of the build takes seconds or literally minutes. Here are a few suggestions:
- Convert more files into ReScript =). Fewer files going through fewer parts of the JS pipeline helps a ton.
- Careful with bringing in more dependencies: libraries, syntax transforms (e.g. the unofficially supported PPX), build step loaders, etc. The bulk of these dragging down the editing & building experience might out-weight the API benefits they provide.
## Hot Reloading
Hot reloading refers to maintaining a dev server and listening to file changes in a way that allows the server to pipe some delta changes right into the currently running browser page. This provides a relatively fast iteration workflow while working in specific frameworks.
However, hot reloading is fragile by nature, and counts on the occasional inconsistencies (bad state, bad eval, etc.) and the heavy devserver setup/config being less of a hassle than the benefits it provides. We err on the side of caution and stability in general, and decided not to provide a built-in hot reloading _yet_. **Note**: you can still use the hot reloading facility provided by your JS build pipeline.
---
title: "Pinned Dependencies"
metaTitle: "Pinned Dependencies"
description: "Handling multiple packages within one ReScript project with pinned dependencies"
canonical: "/docs/manual/v11.0.0/build-pinned-dependencies"
---
# Pinned Dependencies
Usually we'd recommend to use ReScript in a single-codebase style by using one `rescript.json` file for your whole codebase.
There are scenarios where you still want to connect and build multiple independent ReScript packages for one main project though (`npm` workspaces-like "monorepos"). This is where `pinned-dependencies` come into play.
## Package Types
Before we go into detail, let's first explain all the different package types recognized by the build system:
- Toplevel (this is usually the final app you are building, which has dependencies to other packages)
- Pinned dependencies (these are your local packages that should always rebuild when you build your toplevel, those should be listed in `bs-dependencies` and `pinned-dependencies`)
- Normal dependencies (these are packages that are consumed from npm and listed via `bs-dependencies`)
Whenever a package is being built (`rescript build`), the build system will build the toplevel package with its pinned-dependencies. So any changes made in a pinned dependency will automatically be reflected in the final app.
## Build System Package Rules
The build system respects the following rules for each package type:
**Toplevel**
- Warnings reported
- Warn-error respected
- Builds dev dependencies
- Builds pinned dependencies
- Runs custom rules
- Package-specs like JavaScript module or CommonJS overrides all its dependencies
**Pinned dependencies**
- Warnings reported
- Warn-error respected
- Ignores pinned dependencies
- Builds dev dependencies
- Runs custom rules
**Normal dependencies**
- Warnings, warn-error ignored
- Ignores dev directories
- Ignores pinned dependencies
- Ignores custom generator rules
So with that knowledge in mind, let's dive into some more concrete examples to see our pinned dependencies in action.
## Examples
### Yarn workspaces
Let's assume we have a codebase like this:
```
myproject/
app/
- src/App.res
- rescript.json
common/
- src/Header.res
- rescript.json
myplugin/
- src/MyPlugin.res
- rescript.json
package.json
```
Our `package.json` file within our codebase root would look like this:
```json
{
"name": "myproject",
"private": true,
"workspaces": {
"packages": ["app", "common", "myplugin"]
}
}
```
Our `app` folder would be our toplevel package, consuming our `common` and `myplugin` packages as `pinned-dependencies`. The configuration for `app/rescript.json` looks like this:
```json
{
"name": "app",
"version": "1.0.0",
"sources": {
"dir": "src",
"subdirs": true
},
/* ... */
"bs-dependencies": ["common", "myplugin"],
"pinned-dependencies": ["common", "myplugin"]
/* ... */
}
```
Now, whenever we are running `rescript build` within our `app` package, the compiler would always rebuild any changes within its pinned dependencies as well.
**Important:** ReScript will not rebuild any `pinned-dependencies` in watch mode! This is due to the complexity of file watching, so you'd need to set up your own file-watcher process that runs `rescript build` on specific file changes.
---
title: "If-Else & Loops"
description: "If, else, ternary, for, and while"
canonical: "/docs/manual/v11.0.0/control-flow"
---
# If-Else & Loops
ReScript supports `if`, `else`, ternary expression (`a ? b : c`), `for` and `while`.
ReScript also supports our famous pattern matching, which will be covered in [its own section](pattern-matching-destructuring.md)
## If-Else & Ternary
Unlike its JavaScript counterpart, ReScript's `if` is an expression; they evaluate to their body's content:
```res
let message = if isMorning {
"Good morning!"
} else {
"Hello!"
}
```
```js
var message = isMorning ? "Good morning!" : "Hello!";
```
**Note:** an `if-else` expression without the final `else` branch implicitly gives `()` (aka the `unit` type). So this:
```res
if showMenu {
displayMenu()
}
```
```js
if (showMenu) {
displayMenu();
}
```
is basically the same as:
```res
if showMenu {
displayMenu()
} else {
()
}
```
```js
if (showMenu) {
displayMenu()
}
```
Here's another way to look at it. This is clearly wrong:
```res
let result = if showMenu {
1 + 2
}
```
It'll give a type error, saying basically that the implicit `else` branch has the type `unit` while the `if` branch has type `int`. Intuitively, this makes sense: what would `result`'s value be, if `showMenu` was `false`?
We also have ternary sugar, but **we encourage you to prefer if-else when possible**.
```res
let message = isMorning ? "Good morning!" : "Hello!"
```
```js
var message = isMorning ? "Good morning!" : "Hello!";
```
**`if-else` and ternary are much less used** in ReScript than in other languages; [Pattern-matching](pattern-matching-destructuring.md) kills a whole category of code that previously required conditionals.
## For Loops
For loops iterate from a starting value up to (and including) the ending value.
```res
for i in startValueInclusive to endValueInclusive {
Console.log(i)
}
```
```js
for(var i = startValueInclusive; i <= endValueInclusive; ++i){
console.log(i);
}
```
```res example
// prints: 1 2 3, one per line
for x in 1 to 3 {
Console.log(x)
}
```
```js
for(var x = 1; x <= 3; ++x){
console.log(x);
}
```
You can make the `for` loop count in the opposite direction by using `downto`.
```res
for i in startValueInclusive downto endValueInclusive {
Console.log(i)
}
```
```js
for(var i = startValueInclusive; i >= endValueInclusive; --i){
console.log(i);
}
```
```res example
// prints: 3 2 1, one per line
for x in 3 downto 1 {
Console.log(x)
}
```
```js
for(var x = 3; x >= 1; --x){
console.log(x);
}
```
## While Loops
While loops execute its body code block while its condition is true.
```res
while testCondition {
// body here
}
```
```js
while (testCondition) {
// body here
}
```
### Tips & Tricks
There's no loop-breaking `break` keyword (nor early `return` from functions, for that matter) in ReScript. However, we can break out of a while loop easily through using a [mutable binding](mutation.md).
```res example
let break = ref(false)
while !break.contents {
if Math.random() > 0.3 {
break := true
} else {
Console.log("Still running")
}
}
```
```js
var $$break = {
contents: false
};
while(!$$break.contents) {
if (Math.random() > 0.3) {
$$break.contents = true;
} else {
console.log("Still running");
}
};
```
---
title: "Converting from JS"
description: "How to convert to ReScript with an existing JS codebase"
canonical: "/docs/manual/v11.0.0/converting-from-js"
---
# Converting from JS
ReScript offers a unique project conversion methodology which:
- Ensures minimal disruption to your teammates (very important!).
- Remove the typical friction of verifying conversion's correctness and performance guarantees.
- Doesn't force you to search for pre-made binding libraries made by others. **ReScript doesn't need the equivalent of TypeScript's `DefinitelyTyped`**.
## Step 1: Install ReScript
Run `npm install rescript` on your project, then imitate our [New Project](installation#new-project) workflow by adding a `rescript.json` at the root. Then start `npx rescript -w`.
## Step 2: Copy Paste the Entire JS File
Let's work on converting a file called `src/main.js`.
```js
const school = require('school');
const defaultId = 10;
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return school.getStudentById(defaultId);
}
}
```
First, copy the entire file content over to a new file called `src/Main.res` by using our [`%%raw` JS embedding trick](embed-raw-javascript):
```res example
%%raw(`
const school = require('school');
const defaultId = 10;
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return school.getStudentById(defaultId);
}
}
`)
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
const school = require('school');
const defaultId = 10;
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return school.getStudentById(defaultId);
}
}
/* Not a pure module */
```
Add this file to `rescript.json`:
```json
"sources": {
"dir" : "src",
"subdirs" : true
},
```
Open an editor tab for `src/Main.res.js`. Do a command-line `diff -u src/main.js src/Main.res.js`. Aside from whitespaces, you should see only minimal, trivial differences. You're already a third of the way done!
**Always make sure** that at each step, you keep the ReScript output `.res.js` file open to compare against the existing JavaScript file. Our compilation output is very close to your hand-written JavaScript; you can simply eye the difference to catch conversion bugs!
## Step 3: Extract Parts into Idiomatic ReScript
Let's turn the `defaultId` variable into a ReScript let-binding:
```res example
let defaultId = 10
%%raw(`
const school = require('school');
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return school.getStudentById(defaultId);
}
}
`)
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
const school = require('school');
function queryResult(usePayload, payload) {
if usePayload {
return payload.student
} else {
return school.getStudentById(defaultId)
}
}
var defaultId = 10;
exports.defaultId = defaultId;
/* Not a pure module */
```
Check the output. Diff it. Code still works. Moving on! Extract the function:
```res
%%raw(`
const school = require('school');
`)
let defaultId = 10
let queryResult = (usePayload, payload) => {
if usePayload {
payload.student
} else {
school.getStudentById(defaultId)
}
}
```
```js
```
Format the code: `./node_modules/.bin/rescript format src/Main.res`.
We have a type error: "The record field student can't be found". That's fine! **Always ensure your code is syntactically valid first**. Fixing type errors comes later.
## Step 4: Add `external`s, Fix Types
The previous type error is caused by `payload`'s record declaration (which supposedly contains the field `student`) not being found. Since we're trying to convert as quickly as possible, let's use our [object](object) feature to avoid needing type declaration ceremonies:
```res
%%raw(`
const school = require('school');
`)
let defaultId = 10
let queryResult = (usePayload, payload) => {
if usePayload {
payload["student"]
} else {
school["getStudentById"](defaultId)
}
}
```
```js
```
Now this triggers the next type error, that `school` isn't found. Let's use [`external`](external) to bind to that module:
```res example
@module external school: 'whatever = "school"
let defaultId = 10
let queryResult = (usePayload, payload) => {
if usePayload {
payload["student"]
} else {
school["getStudentById"](defaultId)
}
}
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
var School = require("school");
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return School.getStudentById(10);
}
}
var defaultId = 10;
exports.defaultId = defaultId;
exports.queryResult = queryResult;
/* school Not a pure module */
```
We hurrily typed `school` as a polymorphic `'whatever` and let its type be inferred by its usage below. The inference is technically correct, but within the context of bringing it a value from JavaScript, slightly dangerous. This is just the interop trick we've shown in the [`external`](external) page.
Anyway, the file passes the type checker again. Check the `.res.js` output, diff with the original `.js`; we've now converted a file over to ReScript!
Now, you can delete the original, hand-written `main.js` file, and grep the files importing `main.js` and change them to importing `Main.res.js`.
## (Optional) Step 5: Cleanup
If you prefer more advanced, rigidly typed `payload` and `school`, feel free to do so:
```res example
type school
type student
type payload = {
student: student
}
@module external school: school = "school"
@send external getStudentById: (school, int) => student = "getStudentById"
let defaultId = 10
let queryResult = (usePayload, payload) => {
if usePayload {
payload.student
} else {
school->getStudentById(defaultId)
}
}
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
var School = require("school");
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return School.getStudentById(10);
}
}
var defaultId = 10;
exports.defaultId = defaultId;
exports.queryResult = queryResult;
/* school Not a pure module */
```
We've:
- introduced an opaque types for `school` and `student` to prevent misuse of their values
- typed the payload as a record with only the `student` field
- typed `getStudentById` as the sole method of `student`
Check that the `.res.js` output didn't change. How rigidly to type your JavaScript code is up to you; we recommend not typing them too elaborately; it's sometime an endless chase, and produces diminishing returns, especially considering that the elaborate-ness might turn off your potential teammates.
## Tips & Tricks
In the same vein of idea, **resist the urge to write your own wrapper functions for the JS code you're converting**. Use [`external`s](external), which are guaranteed to be erased in the output. And avoid trying to take the occasion to convert JS data structures into ReScript-specific data structures like variant or list. **This isn't the time for that**.
The moment you produce extra conversion code in the output, your skeptical teammate's mental model might switch from "I recognize this output" to "this conversion might be introducing more problems than it solves. Why are we testing ReScript again?". Then you've lost.
## Conclusion
- Paste the JS code into a new ReScript file as embedded raw JS code.
- Compile and keep the output file open. Check and diff against original JS file. Free regression tests.
- Always make sure your file is syntactically valid. Don't worry about fixing types before that.
- (Ab)use [object](object.md) accesses to quickly convert things over.
- Optionally clean up the types for robustness.
- Don't go overboard and turn off your boss and fellow teammates.
- Proudly display that you've conserved the semantics and performance characteristics during the conversion by showing your teammates the eerily familiar output.
- Get promoted for introducing a new technology the safer, mature way.
---
title: "Editor Plugins"
description: "List of ReScript editor plugins"
canonical: "/docs/manual/v11.0.0/editor-plugins"
---
# Editor Plugins
- [VSCode](https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode)
- [Sublime Text](https://github.com/rescript-lang/rescript-sublime)
- [Vim/Neovim](https://github.com/rescript-lang/vim-rescript)
## Community Supported
We don't officially support these; use them at your own risk!
- [Neovim Tree-sitter](https://github.com/nkrkv/nvim-treesitter-rescript)
- [IDEA](https://github.com/reasonml-editor/reasonml-idea-plugin)
- [Emacs](https://github.com/jjlee/rescript-mode)
- [Zed](https://github.com/humaans/rescript-zed)
---
title: "Embed Raw JavaScript"
description: "Utility syntax to for raw JS usage in ReScript"
canonical: "/docs/manual/v11.0.0/embed-raw-javascript"
---
# Embed Raw JavaScript
## Paste Raw JS Code
First thing first. If you're ever stuck learning ReScript, remember that you can always just paste raw JavaScript code into our source file:
```res example
%%raw(`
// look ma, regular JavaScript!
var message = "hello";
function greet(m) {
console.log(m)
}
`)
```
```js
// look ma, regular JavaScript!
var message = "hello";
function greet(m) {
console.log(m)
}
```
The `%%raw` special ReScript call takes your code string and pastes it as-is into the output. **You've now technically written your first ReScript file!**
(The back tick syntax is a multiline string, similar to JavaScript's. Except for us, no escaping is needed inside the string. More on string in a later section.)
While `%%raw` lets you embed top-level raw JS code, `%raw` lets you embed expression-level JS code:
```res example
let add = %raw(`
function(a, b) {
console.log("hello from raw JavaScript!");
return a + b
}
`)
Console.log(add(1, 2))
```
```js
var add = function(a, b) {
console.log("hello from raw JavaScript!");
return a + b
};
console.log(add(1, 2));
```
The above code:
- declared a ReScript variable `add`,
- with the raw JavaScript value of a function declaration,
- then called that function in ReScript.
If your boss is ever worried that your teammates can't adopt ReScript, just let them keep writing JavaScript inside ReScript files =).
## Debugger
You can also drop a `%debugger` expression in a body:
```res example
let f = (x, y) => {
%debugger
x + y
}
```
```js
function f(x, y) {
debugger;
return x + y | 0;
}
```
Output:
```js
function f(x, y) {
debugger; // JavaScript developer tools will set an breakpoint and stop here
x + y;
}
```
## Tips & Tricks
Embedding raw JS snippets isn't the best way to experience ReScript, though it's also highly useful if you're just starting out. As a matter of fact, the first few ReScript projects were converted through:
- pasting raw JS snippets inside a file
- examining the JS output (identical to the old hand-written JS)
- gradually extract a few values and functions and making sure the output still looks OK
At the end, we get a fully safe, converted ReScript file whose JS output is clean enough that we can confidently assert that no new bug has been introduced during the conversion process.
We have a small guide on this iteration [here](converting-from-js.md). Feel free to peruse it later.
---
title: "Equality and Comparison"
description: "Handling equality and comparison checks"
canonical: "/docs/manual/v11.0.0/equality-comparison"
---
# Equality and Comparison
ReScript has shallow equality `===`, deep equality `==`, and comparison operators `>`, `>=`, `<`, and `<=`.
## Shallow equality
The shallow equality operator `===` compares two values and either compiles to `===` or a `bool` if the equality is known to the compiler.
It behaves the same as the strict equality operator `===` in JavaScript.
Using `===` will never add a runtime cost.
```res
let t1 = 1 === 1 // true
let t2 = "foo" === "foo" // true
let t3 = { "foo": "bar" } === { "foo": "bar"} // false
let doStringsMatch = (s1: string, s2: string) => s1 === s2
```
```js
var t1 = true;
var t2 = "foo" === "foo";
var t3 = ({ foo: "bar" }) === ({ foo: "bar" });
function doStringsMatch(s1, s2) {
return s1 === s2;
}
```
## Deep equality
ReScript has the deep equality operator `==` to check deep equality of two items, which is very different from the loose equality operator like `==` in JavaScript.
When using `==` in ReScript it will never compile to `==` in JavaScript,
it will either compile to `===`, a runtime call to an internal function that deeply compares the equality, or a `bool` if the equality is known to the compiler.
```res
let t1 = 1 == 1 // true
let t2 = "foo" == "foo" // true
let t3 = { "foo": "bar" } == { "foo": "bar"} // true
let doStringsMatch = (s1: string, s2: string) => s1 == s2
```
```js
import * as Caml_obj from "./stdlib/caml_obj.js";
var t1 = true;
var t2 = true;
var t3 = Caml_obj.equal({ foo: "bar" }, { foo: "bar" });
function doStringsMatch(s1, s2) {
return s1 === s2;
}
```
`==` will compile to `===` (or a `bool` if the compiler can determine equality) when:
- Comparing `string`, `char`, `int`, `float`, `bool`, or `unit`
- Comparing variants or polymorphic variants that do not have constructor values
`==` will compile to a runtime check for deep equality when:
- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression `Re.t`
- Comparing variants or polymorphic variants that have constructor values
> When using `==` pay close attention to the JavaScript output if you're not sure what `==` will compile to.
## Comparison
ReScript has operators for comparing values that compile to the the same operator in JS, a runtime check using an internal function, or a `bool` if the equality is known to the compiler,
| operator | comparison |
| --- | ----------- |
| `>` | greater than |
| `>=` | greater than or equal |
| `<` | less than |
| `<=` | less than or equal |
Comparison can be done on any type.
An operator will compile to the same operator (or a `bool` if the compiler can determine equality) when:
- Comparing `int`, `float`, `string`, `char`, `bool`
An operator will compile to a runtime check for deep equality when:
- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression (`Re.t`)
- Comparing variants or polymorphic variants
```res
let compareInt = (a: int, b: int) => a > b
let t1 = 1 > 10
let compareArray = (a: array, b: array) => a > b
let compareOptions = (a: option, b: option) => a < b
```
```js
import * as Caml_obj from "./stdlib/caml_obj.js";
function compareInt(a, b) {
return a > b;
}
var t1 = false;
var compareArray = Caml_obj.greaterthan;
var compareOptions = Caml_obj.lessthan;
```
## Performance of runtime equality checks
The runtime equality check ReScript uses is quite fast and should be adequate for almost all use cases.
For small objects it can be 2x times faster than alternative deep compare functions such as Lodash's [`_.isEqual`](https://lodash.com/docs/4.17.15#isEqual).
For larger objects instead of using `==` you could manually use a faster alternative such as [fast-deep-compare](https://www.npmjs.com/package/fast-deep-equal), or write a custom comparator function.
[This repo](https://github.com/jderochervlk/rescript-perf) has benchmarks comparing results of different libraries compared to ReScript's built-in equality function.
---
title: "Exception"
description: "Exceptions and exception handling in ReScript"
canonical: "/docs/manual/v11.0.0/exception"
---
# Exception
Exceptions are just a special kind of variant, thrown in **exceptional** cases (don't abuse them!). Consider using the [`option`](null-undefined-option.mdx) or [`result`](api/core/result) type for recoverable errors.
You can create your own exceptions like you'd make a variant (exceptions need to be capitalized too).
```res example
exception InputClosed(string)
// later on
raise(InputClosed("The stream has closed!"))
```
```js
import * as Caml_exceptions from "./stdlib/caml_exceptions.js";
var InputClosed = /* @__PURE__ */Caml_exceptions.create("Playground.InputClosed");
throw {
RE_EXN_ID: InputClosed,
_1: "The stream has closed!",
Error: new Error()
};
```
## Built-in Exceptions
ReScript has some built-in exceptions:
### `Not_found`
```res prelude
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
}
```
```js
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
function getItem(item) {
if (item === 3) {
return 1;
}
throw {
RE_EXN_ID: "Not_found",
Error: new Error()
};
}
var result;
try {
result = getItem(2);
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === "Not_found") {
result = 0;
} else {
throw exn;
}
}
```
Note that the above is just for demonstration purposes; in reality, you'd return an `option` directly from `getItem` and avoid the `try` altogether.
You can directly match on exceptions _while_ getting another return value from a function:
```res prelude
switch list{1, 2, 3}->List.getExn(4) {
| item => Console.log(item)
| exception Not_found => Console.log("No such item found!")
}
```
```js
import * as Core__List from "./stdlib/core__List.js";
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
var exit = 0;
var item;
try {
item = Core__List.getExn({
hd: 1,
tl: {
hd: 2,
tl: {
hd: 3,
tl: /* [] */0
}
}
}, 4);
exit = 1;
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === "Not_found") {
console.log("No such item found!");
} else {
throw exn;
}
}
if (exit === 1) {
console.log(item);
}
```
### `Invalid_argument`
Used to check if argument is valid. This exception takes a string.
```res example
let divide = (a, b) =>
if b == 0 {
raise(Invalid_argument("Denominator is zero"))
} else {
a / b
}
// catch error
try divide(2, 0)->Console.log catch {
| Invalid_argument(msg) => Console.log(msg) // Denominator is zero
}
```
```js
import * as Caml_int32 from "./stdlib/caml_int32.js";
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
function divide(a, b) {
if (b === 0) {
throw {
RE_EXN_ID: "Invalid_argument",
_1: "Denominator is zero",
Error: new Error()
};
}
return Caml_int32.div(a, b);
}
try {
console.log(divide(2, 0));
}
catch (raw_msg){
var msg = Caml_js_exceptions.internalToOCamlException(raw_msg);
if (msg.RE_EXN_ID === "Invalid_argument") {
console.log(msg._1);
} else {
throw msg;
}
}
```
### `Assert_failure`
Raise when you use `assert(condition)` and `condition` is false. The arguments
are the location of the `assert` in the source code (file name, line number, column number).
```res example
let decodeUser = (json: JSON.t) =>
switch json {
| Object(userDict) =>
switch (userDict->Dict.get("name"), userDict->Dict.get("age")) {
| (Some(String(name)), Some(Number(age))) => (name, age->Float.toInt)
| _ => assert(false)
}
| _ => assert(false)
}
try decodeUser(%raw("{}"))->Console.log catch {
| Assert_failure(loc) => Console.log(loc) // ("filename", line, col)
}
```
```js
mport * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
function decodeUser(json) {
if (!Array.isArray(json) && (json === null || typeof json !== "object") && typeof json !== "number" && typeof json !== "string" && typeof json !== "boolean") {
throw {
RE_EXN_ID: "Assert_failure",
_1: [
"playground.res",
8,
9
],
Error: new Error()
};
}
if (typeof json === "object" && !Array.isArray(json)) {
var match = json["name"];
var match$1 = json["age"];
if (match !== undefined && !(!Array.isArray(match) && (match === null || typeof match !== "object") && typeof match !== "number" && typeof match !== "string" && typeof match !== "boolean") && typeof match === "string" && match$1 !== undefined && !(!Array.isArray(match$1) && (match$1 === null || typeof match$1 !== "object") && typeof match$1 !== "number" && typeof match$1 !== "string" && typeof match$1 !== "boolean") && typeof match$1 === "number") {
return [
match,
match$1 | 0
];
}
throw {
RE_EXN_ID: "Assert_failure",
_1: [
"playground.res",
6,
11
],
Error: new Error()
};
}
throw {
RE_EXN_ID: "Assert_failure",
_1: [
"playground.res",
8,
9
],
Error: new Error()
};
}
try {
console.log(decodeUser({}));
}
catch (raw_loc){
var loc = Caml_js_exceptions.internalToOCamlException(raw_loc);
if (loc.RE_EXN_ID === "Assert_failure") {
console.log(loc._1);
} else {
throw loc;
}
}
```
### `Failure`
Exception raised to signal that the given arguments do not make sense. This
exception takes a string as an argument.
```res example
let isValidEmail = email => {
let hasAtSign = String.includes(email, "@")
let hasDot = String.includes(email, ".")
if !(hasAtSign && hasDot) {
raise(Failure("Invalid email address"))
} else {
true
}
}
let isValid = try isValidEmail("rescript.org") catch {
| Failure(msg) => {
Console.error(msg)
false
}
}
```
```js
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
function isValidEmail(email) {
var hasAtSign = email.includes("@");
var hasDot = email.includes(".");
if (hasAtSign && hasDot) {
return true;
}
throw {
RE_EXN_ID: "Failure",
_1: "Invalid email address",
Error: new Error()
};
}
var isValid;
try {
isValid = isValidEmail("rescript.org");
}
catch (raw_msg){
var msg = Caml_js_exceptions.internalToOCamlException(raw_msg);
if (msg.RE_EXN_ID === "Failure") {
console.error(msg._1);
isValid = false;
} else {
throw msg;
}
}
```
### `Division_by_zero`
Exception raised by integer division and remainder operations when their second argument is zero.
```res example
// ReScript raise `Division_by_zero` if the denominator is zero
let result = try Some(10 / 0) catch {
| Division_by_zero => None
}
Console.log(result) // None
```
```js
import * as Caml_int32 from "./stdlib/caml_int32.js";
import * as Caml_js_exceptions from "./stdlib/caml_js_exceptions.js";
var result;
try {
result = Caml_int32.div(10, 0);
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === "Division_by_zero") {
result = undefined;
} else {
throw exn;
}
}
console.log(result);
```
## 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`](api/js/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`:
```res example
let myTest = () => {
Exn.raiseError("Hello!")
}
```
```js
var Js_exn = require("./stdlib/js_exn.js");
function myTest() {
return Js_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!
```res example
exception BadArgument({myMessage: string})
let myTest = () => {
raise(BadArgument({myMessage: "Oops!"}))
}
```
```js
var Caml_exceptions = require("./stdlib/caml_exceptions.js");
var BadArgument = Caml_exceptions.create("Playground.BadArgument");
function myTest() {
throw {
RE_EXN_ID: BadArgument,
myMessage: "Oops!",
Error: new Error()
};
}
```
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` (`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...
---
title: "Extensible Variant"
description: "Extensible Variants in ReScript"
canonical: "/docs/manual/v11.0.0/extensible-variant"
---
# Extensible Variant
Variant types are usually constrained to a fixed set of constructors. There may be very rare cases where you still want to be able to add constructors to a variant type even after its initial type declaration. For this, we offer extensible variant types.
## Definition and Usage
```res example
type t = ..
type t += Other
type t +=
| Point(float, float)
| Line(float, float, float, float)
```
```js
var Caml_exceptions = require("./stdlib/caml_exceptions.js");
var Other = Caml_exceptions.create("Playground.Other");
var Point = Caml_exceptions.create("Playground.Point");
var Line = Caml_exceptions.create("Playground.Line");
```
The `..` in the type declaration above defines an extensible variant `type t`. The `+=` operator is then used to add constructors to the given type.
**Note:** Don't forget the leading `type` keyword when using the `+=` operator!
## Pattern Matching Caveats
Extensible variants are open-ended, so the compiler will not be able to exhaustively pattern match all available cases. You will always need to provide a default `_` case for every `switch` expression.
```res
let print = v =>
switch v {
| Point(x, y) => Console.log2("Point", (x, y))
| Line(ax, ay, bx, by) => Console.log2("Line", (ax, ay, bx, by))
| Other
| _ => Console.log("Other")
}
```
```js
function print(v) {
if (v.RE_EXN_ID === Point) {
console.log("Point", [v._1, v._2]);
} else if (v.RE_EXN_ID === Line) {
console.log("Line", [v._1, v._2, v._3, v._4]);
} else {
console.log("Other");
}
}
```
## Tips & Tricks
**Fun fact:** In ReScript, [exceptions](./exception) are actually extensible variants under the hood, so `exception UserError(string)` is equivalent to `type exn += UserError(string)`. It's one of the very few use-case where extensible variants make sense.
We usually recommend sticking with common [variants](./variant) as much as possible to reap the benefits of exhaustive pattern matching.
---
title: "External (Bind to Any JS Library)"
description: "The external keyword"
canonical: "/docs/manual/v11.0.0/external"
---
# External (Bind to Any JS Library)
`external` is the primary ReScript features for bringing in and using JavaScript values.
`external` is like a let binding, but:
- The right side of `=` isn't a value; it's the name of the JS value you're referring to.
- The type for the binding is mandatory, since we need to know what the type of that JS value is.
- Can only exist at the top level of a file or module.
```res example
@val external setTimeout: (unit => unit, int) => float = "setTimeout"
```
```js
// Empty output
```
There are several kinds of `external`s, differentiated and/or augmented through the [attribute](attribute.md) they carry. This page deals with the general, shared mechanism behind most `external`s. The different `external`s are documented in their respective pages later. A few notable ones:
- `@val`, `@scope`: [bind to global JS values](bind-to-global-js-values).
- `@module`: [bind to JS imported/exported values](import-from-export-to-js).
- `@send`: [bind to JS methods](bind-to-js-function).
You can also use our [Syntax Lookup](/syntax-lookup) tool to find them.
Related: see also our [list of external decorators](interop-cheatsheet#list-of-decorators).
## Usage
Once declared, you can use an `external` as a normal value, just like a let binding.
## Tips & Tricks
`external` + ReScript objects are a wonderful combination for quick prototyping. Check the JS output tab:
```res example
// The type of document is just some random type 'a
// that we won't bother to specify
@val external document: 'a = "document"
// call a method
document["addEventListener"]("mouseup", _event => {
Console.log("clicked!")
})
// get a property
let loc = document["location"]
// set a property
document["location"]["href"] = "rescript-lang.org"
```
```js
document.addEventListener("mouseup", function(_event) {
console.log("clicked!");
});
var loc = document.location;
document.location.href = "rescript-lang.org";
```
We've specified `document`'s type as `'a`, aka a placeholder type that's polymorphic. Any value can be passed there, so you're not getting much type safety (except the inferences at various call sites). However, this is excellent for quickly getting started using a JavaScript library in ReScript **without needing the equivalent of a repository of typed bindings** like TypeScript's `DefinitelyTyped` repo.
However, if you want to more rigidly bind to the JavaScript library you want, keep reading the next few interop pages.
## Performance & Output Readability
`external`s declarations are inlined into their callers during compilation, **and completely disappear from the JS output**. This means any time you use one, you can be sure that you're not incurring extra JavaScript \<-> ReScript conversion cost.
Additionally, no extra ReScript-specific runtime is better for output readability.
> **Note:** do also use `external`s and the `@blabla` attributes in the interface files. Otherwise the inlining won't happen.
## Design Decisions
ReScript takes interoperating with existing code very seriously. Our type system has very strong guarantees. However, such strong feature also means that, without a great interop system, it'd be very hard to gradually convert a codebase over to ReScript. Fortunately, our interop are comprehensive and cooperate very well with most existing JavaScript code.
The combination of a sound type system + great interop means that we get the benefits of a traditional gradual type system regarding incremental codebase coverage & conversion, without the downside of such gradual type system: complex features to support existing patterns, slow analysis, diminishing return in terms of type coverage, etc.
---
title: "FAQ"
description: "Frequently asked questions about ReScript and its ecosystem"
canonical: "/docs/manual/v11.0.0/faq"
---
# Frequently Asked Questions
**What's the goal of this project?**
We aim to provide the best typed language experience for the JavaScript platform.
**What’s the relationship with BuckleScript?**
BuckleScript is ReScript's old branding, with a sharper focus on proper JS support and familiarity which we previously couldn't achieve to the degree we wanted, due to us needing to cater to various different crowds.
**What’s ReScript's relationship with OCaml?**
We reuse and adjust the excellent type system and lots of other high quality components from OCaml for JS experience.
Additionally, ReScript provides its own syntax, build system, IDE, backend, JS interop, extra language features, etc.
The ReScript toolchain is developed using OCaml, however, the version of ReScript is decoupled against the version of OCaml,
ReScript compiler should build against any reasonable modern version of OCaml compiler.
For the majority of ReScript users, they don't need to learn OCaml or use OCaml toolchain to be productive in ReScript.
**What’s the relationship with Reason?**
See [here](/blog/bucklescript-is-rebranding). Reason is a syntax layer for OCaml that BuckleScript also adopted. The current ReScript compiler also supports the old Reason syntax v3.6 for backward compatibility. We will support it for a long time to make sure existing users do not get breaking changes.
**I come from Reason/OCaml. Will ReScript keep supporting X?**
Please see our [blog post](/blog/a-note-on-bucklescripts-future-commitments) on this matter.
**Where can I see the docs in old Reason/OCaml syntax?**
Switch the doc version to `v8.0.0` in the sidebar on the left!
**Will ReScript support native compilation eventually?**
Our focus is a solid JS story right now. In the future, if there’s strong demand, we might consider it.
**What’s the current state of ReScript?**
Currently, we're actively working on the editor support.
**When will we get the `async/await` keywords?**
async/await has arrived in ReScript 10.1!
**Why create a new syntax?**
The existing Reason syntax is owned by a different team with a different vision. Reason aims to be 100% compatible with OCaml syntax and to support all versions of OCaml. In the last few years, we've drawn the conclusion that it’s very hard to deliver such goal without sacrificing user experience. The other reason is that we feel it’s better to have the same vision as a team so that we can make more coherent decisions.
**Who is behind the project?**
The ReScript team (Hongbo, Cheng, Cristiano, Maxim, Patrick, Ricky).
**We have a new forum; will we also have our own Discord?**
Not now. We've found that too much important information get casually passed in Discord then lost within the noise. We prefer folks to communicate on the [forum](https://forum.rescript-lang.org). This is nicer to the less active members.
The team doesn't use the old Discord anymore. We encourage you to move your questions to the forum instead.
---
title: "Function"
description: "Function syntax in ReScript"
canonical: "/docs/manual/v11.0.0/function"
---
# Function
_Cheat sheet for the full function syntax at the end_.
ReScript functions are declared with an arrow and return an expression, just like JS functions. They compile to clean JS functions too.
```res prelude
let greet = (name) => "Hello " ++ name
```
```js
function greet(name) {
return "Hello " + name;
}
```
This declares a function and assigns to it the name `greet`, which you can call like so:
```res example
greet("world!") // "Hello world!"
```
```js
greet("world!");
```
Multi-arguments functions have arguments separated by comma:
```res example
let add = (x, y, z) => x + y + z
add(1, 2, 3) // 6
```
```js
function add(x, y, z) {
return (x + y | 0) + z | 0;
}
```
For longer functions, you'd surround the body with a block:
```res example
let greetMore = (name) => {
let part1 = "Hello"
part1 ++ " " ++ name
}
```
```js
function greetMore(name) {
return "Hello " + name;
}
```
If your function has no argument, just write `let greetMore = () => {...}`.
## Labeled Arguments
Multi-arguments functions, especially those whose arguments are of the same type, can be confusing to call.
```res
let addCoordinates = (x, y) => {
// use x and y here
}
// ...
addCoordinates(5, 6) // which is x, which is y?
```
```js
function addCoordinates(x, y) {
// use x and y here
}
addCoordinates(5, 6);
```
You can attach labels to an argument by prefixing the name with the `~` symbol:
```res
let addCoordinates = (~x, ~y) => {
// use x and y here
}
// ...
addCoordinates(~x=5, ~y=6)
```
```js
function addCoordinates(x, y) {
// use x and y here
}
addCoordinates(5, 6);
```
You can provide the arguments in **any order**:
```res
addCoordinates(~y=6, ~x=5)
```
```js
addCoordinates(5, 6);
```
The `~x` part in the declaration means the function accepts an argument labeled `x` and can refer to it in the function body by the same name. You can also refer to the arguments inside the function body by a different name for conciseness:
```res
let drawCircle = (~radius as r, ~color as c) => {
setColor(c)
startAt(r, r)
// ...
}
drawCircle(~radius=10, ~color="red")
```
```js
function drawCircle(r, c) {
setColor(c);
return startAt(r, r);
}
drawCircle(10, "red");
```
As a matter of fact, `(~radius)` is just a shorthand for `(~radius as radius)`.
Here's the syntax for typing the arguments:
```res
let drawCircle = (~radius as r: int, ~color as c: string) => {
// code here
}
```
```js
function drawCircle(r, c) {
// code here
}
```
## Optional Labeled Arguments
Labeled function arguments can be made optional during declaration. You can then omit them when calling the function.
```res
// radius can be omitted
let drawCircle = (~color, ~radius=?) => {
setColor(color)
switch radius {
| None => startAt(1, 1)
| Some(r_) => startAt(r_, r_)
}
}
```
```js
var Caml_option = require("./stdlib/caml_option.js");
function drawCircle(color, radius) {
setColor(color);
if (radius === undefined) {
return startAt(1, 1);
}
var r_ = Caml_option.valFromOption(radius);
return startAt(r_, r_);
}
```
When given in this syntax, `radius` is **wrapped** in the standard library's `option` type, defaulting to `None`. If provided, it'll be wrapped with a `Some`. So `radius`'s type value is `None | Some(int)` here.
More on `option` type [here](null-undefined-option.md).
### Signatures and Type Annotations
Functions with optional labeled arguments can be confusing when it comes to signature and type annotations. Indeed, the type of an optional labeled argument looks different depending on whether you're calling the function, or working inside the function body. Outside the function, a raw value is either passed in (`int`, for example), or left off entirely. Inside the function, the parameter is always there, but its value is an option (`option`). This means that the type signature is different, depending on whether you're writing out the function type, or the parameter type annotation. The first being a raw value, and the second being an option.
If we get back to our previous example and both add a signature and type annotations to its argument, we get this:
```res
let drawCircle: (~color: color, ~radius: int=?) => unit =
(~color: color, ~radius: option=?) => {
setColor(color)
switch radius {
| None => startAt(1, 1)
| Some(r_) => startAt(r_, r_)
}
}
```
```js
function drawCircle(color, radius) {
setColor(color);
if (radius !== undefined) {
return startAt(radius, radius);
} else {
return startAt(1, 1);
}
}
```
The first line is the function's signature, we would define it like that in an interface file (see [Signatures](module.md#signatures)). The function's signature describes the types that the **outside world** interacts with, hence the type `int` for `radius` because it indeed expects an `int` when called.
In the second line, we annotate the arguments to help us remember the types of the arguments when we use them **inside** the function's body, here indeed `radius` will be an `option` inside the function.
So if you happen to struggle when writing the signature of a function with optional labeled arguments, try to remember this!
### Explicitly Passed Optional
Sometimes, you might want to forward a value to a function without knowing whether the value is `None` or `Some(a)`. Naively, you'd do:
```res
let result =
switch payloadRadius {
| None => drawCircle(~color)
| Some(r) => drawCircle(~color, ~radius=r)
}
```
```js
var r = payloadRadius;
var result = r !== undefined
? drawCircle(color, Caml_option.valFromOption(r))
: drawCircle(color);
```
This quickly gets tedious. We provide a shortcut:
```res
let result = drawCircle(~color, ~radius=?payloadRadius)
```
```js
var result = drawCircle(1, undefined);
```
This means "I understand `radius` is optional, and that when I pass it a value it needs to be an `int`, but I don't know whether the value I'm passing is `None` or `Some(val)`, so I'll pass you the whole `option` wrapper".
### Optional with Default Value
Optional labeled arguments can also be provided a default value. In this case, they aren't wrapped in an `option` type.
```res
let drawCircle = (~radius=1, ~color) => {
setColor(color)
startAt(radius, radius)
}
```
```js
function drawCircle(radiusOpt, color) {
var radius = radiusOpt !== undefined ? radiusOpt : 1;
setColor(color);
return startAt(radius, radius);
}
```
## Recursive Functions
ReScript chooses the sane default of preventing a function to be called recursively within itself. To make a function recursive, add the `rec` keyword after the `let`:
```res example
let rec neverTerminate = () => neverTerminate()
```
```js
function neverTerminate(_param) {
while(true) {
_param = undefined;
continue ;
};
}
```
A simple recursive function may look like this:
```res example
// Recursively check every item on the list until one equals the `item`
// argument. If a match is found, return `true`, otherwise return `false`
let rec listHas = (list, item) =>
switch list {
| list{} => false
| list{a, ...rest} => a === item || listHas(rest, item)
}
```
```js
function listHas(_list, item) {
while(true) {
var list = _list;
if (!list) {
return false;
}
if (list.hd === item) {
return true;
}
_list = list.tl;
continue ;
};
}
```
Recursively calling a function is bad for performance and the call stack. However, ReScript intelligently compiles [tail recursion](https://stackoverflow.com/questions/33923/what-is-tail-recursion) into a fast JavaScript loop. Try checking the JS output of the above code!
### Mutually Recursive Functions
Mutually recursive functions start like a single recursive function using the
`rec` keyword, and then are chained together with `and`:
```res example
let rec callSecond = () => callFirst()
and callFirst = () => callSecond()
```
```js
function callSecond(_param) {
while(true) {
_param = undefined;
continue ;
};
}
function callFirst(_param) {
while(true) {
_param = undefined;
continue ;
};
}
```
## Partial Application
**Since 11.0**
To partially apply a function, use the explicit `...` syntax.
```res
let add = (a, b) => a + b
let addFive = add(5, ...)
```
```js
function add(a, b) {
return a + b | 0;
}
function addFive(extra) {
return 5 + extra | 0;
}
```
## Async/Await
Just as in JS, an async function can be declared by adding `async` before the definition, and `await` can be used in the body of such functions.
The output looks like idiomatic JS:
```res example
let getUserName = async (userId) => userId
let greetUser = async (userId) => {
let name = await getUserName(userId)
"Hello " ++ name ++ "!"
}
```
```js
async function greetUser(userId) {
var name = await getUserName(userId);
return "Hello " + name + "!";
}
```
The return type of `getUser` is inferred to be `promise`.
Similarly, `await getUserName(userId)` returns a `string` when the function returns `promise`.
Using `await` outside of an `async` function (including in a non-async callback to an async function) is an error.
### Ergonomic error handling
Error handling is done by simply using `try`/`catch`, or a switch with an `exception` case, just as in functions that are not async.
Both JS exceptions and exceptions defined in ReScript can be caught. The compiler takes care of packaging JS exceptions into the builtin `JsError` exception:
```res example
exception SomeReScriptException
let somethingThatMightThrow = async () => raise(SomeReScriptException)
let someAsyncFn = async () => {
switch await somethingThatMightThrow() {
| data => Some(data)
| exception JsError(_) => None
| exception SomeReScriptException => None
}
}
```
```js
var SomeReScriptException = /* @__PURE__ */Caml_exceptions.create("Example.SomeReScriptException");
async function someAsyncFn(param) {
var data;
try {
data = await somethingThatMightThrow(undefined);
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === "JsError") {
return ;
}
if (exn.RE_EXN_ID === SomeReScriptException) {
return ;
}
throw exn;
}
return data;
}
```
## The ignore() Function
Occasionally you may want to ignore the return value of a function. ReScript provides an `ignore()` function that discards the value of its argument and returns `()`:
```res
mySideEffect()->Promise.catch(handleError)->ignore
setTimeout(myFunc, 1000)->ignore
```
```js
$$Promise.$$catch(mySideEffect(), function (prim) {
return handleError(prim);
});
setTimeout(function (prim) {
myFunc();
}, 1000);
```
## Tips & Tricks
Cheat sheet for the function syntaxes:
### Declaration
```res
// anonymous function
(x, y) => 1
// bind to a name
let add = (x, y) => 1
// labeled
let add = (~first as x, ~second as y) => x + y
// with punning sugar
let add = (~first, ~second) => first + second
// labeled with default value
let add = (~first as x=1, ~second as y=2) => x + y
// with punning
let add = (~first=1, ~second=2) => first + second
// optional
let add = (~first as x=?, ~second as y=?) => switch x {...}
// with punning
let add = (~first=?, ~second=?) => switch first {...}
```
#### With Type Annotation
```res
// anonymous function
(x: int, y: int): int => 1
// bind to a name
let add = (x: int, y: int): int => 1
// labeled
let add = (~first as x: int, ~second as y: int) : int => x + y
// with punning sugar
let add = (~first: int, ~second: int) : int => first + second
// labeled with default value
let add = (~first as x: int=1, ~second as y: int=2) : int => x + y
// with punning sugar
let add = (~first: int=1, ~second: int=2) : int => first + second
// optional
let add = (~first as x: option=?, ~second as y: option=?) : int => switch x {...}
// with punning sugar
// note that the caller would pass an `int`, not `option`
// Inside the function, `first` and `second` are `option`.
let add = (~first: option=?, ~second: option=?) : int => switch first {...}
```
### Application
```res
add(x, y)
// labeled
add(~first=1, ~second=2)
// with punning sugar
add(~first, ~second)
// application with default value. Same as normal application
add(~first=1, ~second=2)
// explicit optional application
add(~first=?Some(1), ~second=?Some(2))
// with punning
add(~first?, ~second?)
```
#### With Type Annotation
```res
// labeled
add(~first=1: int, ~second=2: int)
// with punning sugar
add(~first: int, ~second: int)
// application with default value. Same as normal application
add(~first=1: int, ~second=2: int)
// explicit optional application
add(~first=?Some(1): option, ~second=?Some(2): option)
// no punning sugar when you want to type annotate
```
### Standalone Type Signature
```res
// first arg type, second arg type, return type
type add = (int, int) => int
// labeled
type add = (~first: int, ~second: int) => int
// labeled
type add = (~first: int=?, ~second: int=?, unit) => int
```
#### In Interface Files
To annotate a function from the implementation file (`.res`) in your interface file (`.resi`):
```res sig
let add: (int, int) => int
```
The type annotation part is the same as the previous section on With Type Annotation.
**Don't** confuse `let add: myType` with `type add = myType`. When used in `.resi` interface files, the former exports the binding `add` while annotating it as type `myType`. The latter exports the type `add`, whose value is the type `myType`.
---
title: "Generate Converters & Helpers"
description: "All about the @deriving decorator, and how to generate code from types"
canonical: "/docs/manual/v11.0.0/generate-converters-accessors"
---
# Generate Converters & Helpers
**Note**: if you're looking for:
- `@deriving(jsConverter)` for records
- `@deriving({jsConverter: newType})` for records
- `@deriving(abstract)` for records
- `@deriving(jsConverter)` for plain and polymorphic variants
These particular ones are no longer needed. Select a doc version lower than `9.0` in the sidebar to see their old docs.
When using ReScript, you will sometimes come into situations where you want to
- Automatically generate functions that convert between ReScript's internal and JS runtime values (e.g. variants).
- Convert a record type into an abstract type with generated creation, accessor and method functions.
- Generate some other helper functions, such as functions from record attribute names.
You can use the `@deriving` decorator for different code generation scenarios. All different options and configurations will be discussed on this page.
**Note:** Please be aware that extensive use of code generation might make it harder to understand your programs (since the code being generated is not visible in the source code, and you just need to know what kind of functions / values a decorator generates).
## Generate Functions & Plain Values for Variants
Use `@deriving(accessors)` on a variant type to create accessor functions for its constructors.
```res
@deriving(accessors)
type action =
| Click
| Submit(string)
| Cancel;
```
```js
function submit(param_0) {
return /* Submit */[param_0];
}
var click = /* Click */0;
var cancel = /* Cancel */1;
exports.click = click;
exports.submit = submit;
exports.cancel = cancel;
```
Variants constructors with payloads generate functions, payload-less constructors generate plain integers (the internal representation of variants).
**Note**:
- The generated accessors are lower-cased.
- You can now use these helpers on the JavaScript side! But don't rely on their actual values please.
### Usage
```res
let s = submit("hello"); /* gives Submit("hello") */
```
This is useful:
- When you're passing the accessor function as a higher-order function (which plain variant constructors aren't).
- When you'd like the JS side to use these values & functions opaquely and pass you back a variant constructor (since JS has no such thing).
Please note that in case you just want to _pipe a payload into a constructor_, you don't need to generate functions for that. Use the `->` syntax instead, e.g. `"test"->Submit`.
## Generate Field Accessors for Records
Use `@deriving(accessors)` on a record type to create accessors for its record field names.
```res
@deriving(accessors)
type pet = {name: string}
let pets = [{name: "bob"}, {name: "bob2"}]
pets
->Array.map(name)
->Array.joinWith("&")
->Console.log
```
```js
function name(param) {
return param.name;
}
var pets = [
{
name: "bob"
},
{
name: "bob2"
}
];
console.log(Belt_Array.map(pets, name).join("&"));
```
---
title: "Import & Export"
description: "Importing / exporting in ReScript modules"
canonical: "/docs/manual/v11.0.0/import-export"
---
# Import & Export
## Import a Module/File
Unlike JavaScript, ReScript doesn't have or need import statements:
```res
// Inside School.res
let studentMessage = Student.message
```
```js
var Student = require("./Student.res.js");
var studentMessage = Student.message
```
The above code refers to the `message` binding in the file `Student.res`. Every ReScript file is also a module, so accessing another file's content is the same as accessing another module's content!
A ReScript project's file names need to be unique.
## Export Stuff
By default, every file's type declaration, binding and module is exported, aka publicly usable by another file. **This also means those values, once compiled into JS, are immediately usable by your JS code**.
To only export a few selected things, use a `.resi` [interface file](module.md#signatures).
## Work with JavaScript Import & Export
To see how to import JS modules and export stuff for JS consumption, see the JavaScript Interop section's [Import from/Export to JS](import-from-export-to-js.md).
---
title: "Import from / Export to JS"
description: "Importing / exporting JS module content in ReScript"
canonical: "/docs/manual/v11.0.0/import-from-export-to-js"
---
# Import from/Export to JS
You've seen how ReScript's idiomatic [Import & Export](import-export.md) works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.
If you're looking for react-specific interop guidance, check out the [React JS Interop guide](../../react/latest/import-export-reactjs.mdx).
**Note**: due to JS ecosystem's module compatibility issues, our advice of keeping your ReScript file's compiled JS output open in a tab applies here **more than ever**, as you don't want to subtly output the wrong JS module import/export code, on top of having to deal with Babel/Webpack/Jest/Node's CommonJS \<-> JavaScript module compatibility shims.
In short: **make sure your bindings below output what you'd have manually written in JS**.
## Output Format
We support 2 JavaScript import/export formats:
- JavaScript module: `import * from 'MyReScriptFile'` and `export let ...`.
- CommonJS: `require('myFile')` and `module.exports = ...`.
The format is [configurable in via `rescript.json`](build-configuration.md#package-specs).
## Import From JavaScript
### Import a JavaScript Module's Named Export
Use the `module` [external](external.md):
```res example
// Import nodejs' path.dirname
@module("path") external dirname: string => string = "dirname"
let root = dirname("/User/github") // returns "User"
```
```js
import * as Path from "path";
var root = Path.dirname("/User/github");
```
```js
var Path = require("path");
var root = Path.dirname("/User/github");
```
Here's what the `external` does:
- `@module("path")`: pass the name of the JS module; in this case, `"path"`. The string can be anything: `"./src/myJsFile"`, `"@myNpmNamespace/myLib"`, etc.
- `external`: the general keyword for declaring a value that exists on the JS side.
- `dirname`: the binding name you'll use on the ReScript side.
- `string => string`: the type signature of `dirname`. Mandatory for `external`s.
- `= "dirname"`: the name of the variable inside the `path` JS module. There's repetition in writing the first and second `dirname`, because sometime the binding name you want to use on the ReScript side is different than the variable name the JS module exported.
### Import a JavaScript Module As a Single Value
By omitting the string argument to `module`, you bind to the whole JS module:
```res example
@module external leftPad: (string, int) => string = "./leftPad"
let paddedResult = leftPad("hi", 5)
```
```js
import * as LeftPad from "./leftPad";
var paddedResult = LeftPad("hi", 5);
```
```js
var LeftPad = require("./leftPad");
var paddedResult = LeftPad("hi", 5);
```
Depending on whether you're compiling ReScript to JavaScript module or CommonJS, **this feature will generate subtly different code**. Please check both output tabs to see the difference. The JavaScript module output here would be wrong!
### Import an `default` Export
Use the value `default` on the right hand side:
```res example
@module("./student") external studentName: string = "default"
Console.log(studentName)
```
```js
import Student from "./student";
var studentName = Student;
```
### Use Import Attributes
**Since 11.1**
[Import attributes](https://github.com/tc39/proposal-import-attributes) can be used in ReScript, as long as ReScript is configured to output JavaScript module. You do that by passing configuration to the `@module` attribute:
```rescript
@module({from: "./myJson.json", with: {type_: "json", \"some-exotic-identifier": "someValue"}})
external myJson: JSON.t = "default"
Console.log(myJson)
```
```javascript
import MyJsonJson from "./myJson.json" with {"type": "json", "some-exotic-identifier": "someValue"};
var myJson = MyJsonJson;
console.log(myJson);
```
This above imports the local `./myJson.json` file, adding import attributes.
This is how it works:
1. Instead of passing a string or tuple to `@module`, pass a record.
2. This record should have a `from` key. The value of that is where you want the module to be imported from (just like the regular string to `@module` is).
3. It should also have a `with` key, with another record where you put all the import attributes you want emitted.
Notice `\"some-exotic-identifier"` - you'll need to escape any key that's not a valid ReScript record key.
Also notice `type_`. Since `type` is a reserved keyword in ReScript, you can use `type_` instead. It will be output as `type` in the JavaScript code.
## Dynamic Import
Leveraging JavaScript's [dynamic `import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) to reduce bundle size and lazy load code as needed is easy in ReScript. It's also a little bit more convenient than in regular JavaScript because you don't need to keep track of file paths manually with ReScript's module system.
### Dynamically Importing Parts of a Module
Use the `import` function to dynamically import a specific part of a module. Put whatever `let` binding you want to import in there, and you'll get a `promise` back resolving to that specific binding.
Let's look at an example. Imagine the following file `MathUtils.res`:
```rescript
let add = (a, b) => a + b
let sub = (a, b) => a - b
```
Now let's dynamically import the add function in another module, e.g. `App.res`:
```rescript
// App.res
let main = async () => {
let add = await import(MathUtils.add)
let onePlusOne = add(1, 1)
Console.log(onePlusOne)
}
```
```javascript
async function main() {
var add = await import("./MathUtils.mjs").then(function(m) {
return m.add;
});
var onePlusOne = add(1, 1);
console.log(onePlusOne);
}
```
### Dynamically Importing an Entire Module
The syntax for importing a whole module looks a little different, since we are operating on the module syntax level; instead of using `import`, you may simply `await` the module itself:
```rescript
// App.res
let main = async () => {
module Utils = await MathUtils
let twoPlusTwo = Utils.add(2, 2)
Console.log(twoPlusTwo)
}
```
```javascript
async function main() {
var Utils = await import("./MathUtils.mjs");
var twoPlusTwo = Utils.add(2, 2);
console.log(twoPlusTwo);
}
```
## Export To JavaScript
### Export a Named Value
As mentioned in ReScript's idiomatic [Import & Export](import-export.md), every let binding and module is exported by default to other ReScript modules (unless you use a `.resi` [interface file](module#signatures)). If you open up the compiled JS file, you'll see that these values can also directly be used by a _JavaScript_ file too.
### Export a `default` Value
If your JS project uses JavaScript module, you're likely exporting & importing some default values:
```js
// student.js
export default name = "Al";
```
```js
// teacher.js
import studentName from 'student.js';
```
A JavaScript default export is really just syntax sugar for a named export implicitly called `default` (now you know!). So to export a default value from ReScript, you can just do:
```res example
// ReScriptStudent.res
let default = "Bob"
```
```js
var $$default = "Bob";
exports.$$default = $$default;
exports.default = $$default;
// informal transpiler-compatible marker of a default export compiled from JavaScript module
exports.__esModule = true;
```
```js
var $$default = "Bob";
export {
$$default,
$$default as default,
}
```
You can then import this default export as usual on the JS side:
```js
// teacher2.js
import studentName from 'ReScriptStudent.js';
```
If your JavaScript's default import is transpiled by Babel/Webpack/Jest into CommonJS `require`s, we've taken care of that too! See the CommonJS output tab for `__esModule`.
---
title: "Inlining Constants"
description: "Inlining constants"
canonical: "/docs/manual/v11.0.0/inlining-constants"
---
# Inlining Constants
Sometimes, in the JavaScript output, you might want a certain value to be forcefully inlined. For example:
```js
if (process.env.mode === 'development') {
console.log("Dev-only code here!")
}
```
The reason is that your JavaScript bundler (e.g. Webpack) might turn that into:
```js
if ('production' === 'development') {
console.log("Dev-only code here!")
}
```
Then your subsequent Uglifyjs optimization would remove that entire `if` block. This is how projects like ReactJS provide a development mode code with plenty of dev warnings, while ensuring that the uglified (minified) production code is free of those expensive blocks.
So, in ReScript, producing that example `if (process.env.mode === 'development')` output is important. This first try doesn't work:
```res example
@val external process: 'a = "process"
let mode = "development"
if (process["env"]["mode"] === mode) {
Console.log("Dev-only code here!")
}
```
```js
var mode = "development";
if (process.env.mode === mode) {
console.log("Dev-only code here!");
}
```
The JS output shows `if (process.env.mode === mode)`, which isn't what we wanted. To inline `mode`'s value, use `@inline`:
```res example
@val external process: 'a = "process"
@inline
let mode = "development"
if (process["env"]["mode"] === mode) {
Console.log("Dev-only code here!")
}
```
```js
if (process.env.mode === "development") {
console.log("Dev-only code here!");
}
```
Now your resulting JS code can pass through Webpack and Uglifyjs like the rest of your JavaScript code, and that whole `console.log` can be removed.
The inlining currently only works for **string, float and boolean**.
## Tips & Tricks
This is **not** an optimization. This is an edge-case feature for folks who absolutely need particular values inlined for a JavaScript post-processing step, like conditional compilation. Beside the difference in code that the conditional compilation might end up outputting, there's no performance difference between inlining and not inlining simple values in the eyes of a JavaScript engine.
---
title: "Installation"
description: "ReScript installation and setup instructions"
canonical: "/docs/manual/v11.0.0/installation"
---
# Installation
## Notes
With the instructions below, our new standard library [ReScript Core](https://github.com/rescript-lang/rescript-core) will be included by default. (In ReScript 11, it comes as a separate npm package `@rescript/core`. In future versions, it will be included in the `rescript` npm package itself.)
## Prerequisites
- [Node.js](https://nodejs.org/) version >= 14
- One of the following package managers:
- [npm](https://docs.npmjs.com/cli/) (comes with Node.js)
- [yarn](https://yarnpkg.com/) (yarn versions >1 need to set `nodeLinker: node-modules` in `.yarnrc.yml`)
- [pnpm](https://pnpm.io/)
- [bun](https://bun.sh/)
## New Project
The fastest and easiest way to spin up a new ReScript project is with the [create-rescript-app](https://github.com/rescript-lang/create-rescript-app) project generator. You can start it with any of the aforementioned package managers or `npx`.
```sh example
npm create rescript-app@latest
```
```sh
npx create-rescript-app
```
```sh
yarn create rescript-app
```
```sh
pnpm create rescript-app
```
```sh
bun create rescript-app
```
- Follow the steps of the setup.
- Trigger a ReScript build:
```sh
npm run res:build
```
- If you selected the "basic" template, simply run it with:
```sh
node src/Demo.res.js
```
That compiles your ReScript into JavaScript, then uses Node.js to run said JavaScript.
**When taking your first steps with ReScript, we recommend you use our unique workflow of keeping a tab open for the generated JS file** (`.res.js`/`.res.mjs`), so that you can learn how ReScript transforms into JavaScript. Not many languages output clean JavaScript code you can inspect and learn from! With our [VS Code extension](https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode), use the command "ReScript: Open the compiled JS file for this implementation file" to open the generated JS file for the currently active ReScript source file.
During development, instead of running `npm run res:build` each time to compile, use `npm run res:dev` to start a watcher that recompiles automatically after file changes.
## Integrate Into an Existing JS Project
If you already have a JavaScript project into which you'd like to add ReScript you can do that in the following ways:
### Quick Setup
In the root directory of your project, execute:
```sh
npm create rescript-app@latest
```
```sh
npx create-rescript-app
```
```sh
yarn create rescript-app
```
```sh
pnpm create rescript-app
```
```sh
bun create rescript-app
```
`create-rescript-app` will tell you that a `package.json` file has been detected and ask you if it should install ReScript into your project. Just follow the steps accordingly.
### Manual Setup
- Install ReScript locally:
```sh
npm install rescript @rescript/core
```
```sh
yarn add rescript @rescript/core
```
```sh
pnpm install rescript @rescript/core
```
```sh
bun install rescript @rescript/core
```
- Create a ReScript build configuration file (called `rescript.json`) at the root:
```json
{
"name": "your-project-name",
"sources": [
{
"dir": "src", // update this to wherever you're putting ReScript files
"subdirs": true
}
],
"package-specs": [
{
"module": "esmodule",
"in-source": true
}
],
"suffix": ".res.js",
"bs-dependencies": [
"@rescript/core"
],
"bsc-flags": [
"-open RescriptCore"
]
}
```
See [Build Configuration](build-configuration) for more details on `rescript.json`.
- Add convenience `npm` scripts to `package.json`:
```json
"scripts": {
"res:build": "rescript",
"res:dev": "rescript -w"
}
```
Since ReScript compiles to clean readable JS files, the rest of your existing toolchain (e.g. Babel and Webpack) should just work!
Helpful guides:
- [Converting from JS](/docs/manual/latest/converting-from-js).
- [Shared Data Types](shared-data-types).
- [Import from/Export to JS](import-from-export-to-js).
### Integrate with a ReactJS Project
To start a [rescript-react](/docs/react/latest/introduction) app, or to integrate ReScript into an existing ReactJS app, follow the instructions [here](/docs/react/latest/installation).
---
title: "Interop Cheatsheet"
description: "Cheatsheet for various interop scenarios in ReScript"
canonical: "/docs/manual/v11.0.0/interop-cheatsheet"
---
# Interop Cheatsheet
This is a glossary with examples. All the features are described by later pages.
## List of Decorators
> **Note:** In ReScript < 8.3, all our attributes started with the `bs.` prefix. This is no longer needed and our formatter automatically removes them in newer ReScript versions.
### Attributes
- `@as`: [here](attribute#usage), [here](bind-to-js-function#fixed-arguments), [here](bind-to-js-function#constrain-arguments-better) and [here](generate-converters-accessors#usage-3)
- [`@deriving`](generate-converters-accessors#generate-functions--plain-values-for-variants)
- [`@get`](bind-to-js-object#bind-using-special-bs-getters--setters)
- [`@get_index`](bind-to-js-object#bind-using-special-bs-getters--setters)
- [`@inline`](inlining-constants)
- [`@int`](bind-to-js-function#constrain-arguments-better)
- [`@module`](import-from-export-to-js#import-a-javascript-modules-content)
- [`@new`](bind-to-js-object#bind-to-a-js-object-thats-a-class)
- [`@optional`](generate-converters-accessors#optional-labels)
- [`@return`](bind-to-js-function#function-nullable-return-value-wrapping)
- `@send`: [here](bind-to-js-function#object-method) and [here](pipe#js-method-chaining)
- [`@scope`](bind-to-global-js-values#global-modules)
- [`@set`](bind-to-js-object#bind-using-special-bs-getters--setters)
- [`@set_index`](bind-to-js-object#bind-using-special-bs-getters--setters)
- [`@variadic`](bind-to-js-function#variadic-function-arguments)
- [`@string`](bind-to-js-function#constrain-arguments-better)
- [`@this`](bind-to-js-function#modeling-this-based-callbacks)
- [`@uncurry`](bind-to-js-function#extra-solution)
- [`@unwrap`](bind-to-js-function#trick-2-polymorphic-variant--bsunwrap)
- [`@val`](bind-to-global-js-values#global-modules)
- [`@taggedTemplate`](bind-to-js-function#tagged_template-functions)
- [`@deprecated`](attribute#usage)
- [`genType`](https://github.com/reason-association/genType)
- [`@JSX`](jsx)
- `@react.component`: [here](/docs/react/latest/introduction) and [here](https://github.com/reasonml/reason-react)
- [`@warning`](attribute#usage)
- [`@unboxed`](variant#untagged-variants)
### Extension Points
- [`%debugger`](embed-raw-javascript#debugger)
- [`%external`](bind-to-global-js-values#special-global-values)
- [`%raw`](embed-raw-javascript#paste-raw-js-code)
- [`%re`](primitive-types#regular-expression)
- [`%todo`](/syntax-lookup#todo)
## Raw JS
```res example
let add = %raw("(a, b) => a + b")
%%raw("const a = 1")
```
```js
var add = ((a, b) => a + b);
const a = 1
```
## Global Value
```res example
@val external setTimeout: (unit => unit, int) => float = "setTimeout"
```
```js
// Empty output
```
## Global Module's Value
```res example
@val @scope("Math")
external random: unit => float = "random"
let someNumber = random()
@val @scope(("window", "location", "ancestorOrigins"))
external length: int = "length"
```
```js
var someNumber = Math.random();
```
## Nullable
```res example
let a = Some(5) // compiles to 5
let b = None // compiles to undefined
```
```js
var a = 5;
var b;
```
Handling a value that can be `undefined` and `null`, by ditching the `option` type and using `Nullable.t`:
```res example
let jsNull = Nullable.null
let jsUndefined = Nullable.undefined
let result1: Nullable.t = Nullable.make("hello")
let result2: Nullable.t = Nullable.fromOption(Some(10))
let result3: option = Nullable.toOption(Nullable.make(10))
```
```js
import * as Caml_option from "./stdlib/caml_option.js";
import * as Core__Nullable from "./stdlib/core__Nullable.js";
var result2 = Core__Nullable.fromOption(10);
var jsNull = null;
var jsUndefined;
var result1 = "hello";
var result3 = Caml_option.nullable_to_opt(10);
```
## JS Object
- [Bind to a JS object as a ReScript record](bind-to-js-object#bind-to-record-like-js-objects).
- [Bind to a JS object that acts like a hash map](bind-to-js-object#bind-to-hash-map-like-js-object).
- [Bind to a JS object that's a class](bind-to-js-object#bind-to-a-js-object-thats-a-class).
## Function
### Object Method & Chaining
```res example
@send external map: (array<'a>, 'a => 'b) => array<'b> = "map"
@send external filter: (array<'a>, 'a => 'b) => array<'b> = "filter"
[1, 2, 3]
->map(a => a + 1)
->filter(a => mod(a, 2) == 0)
->Console.log
```
```js
console.log(
[1, 2, 3]
.map(function (a) {
return (a + 1) | 0;
})
.filter(function (a) {
return a % 2 === 0;
})
);
```
### Variadic Arguments
```res example
@module("path") @variadic
external join: array => string = "join"
```
```js
// Empty output
```
### Tagged template functions
```res example
// see https://bun.sh/docs/runtime/shell
type result = {exitCode: int}
@module("bun") @taggedTemplate
external sh: (array, array) => promise = "$"
let filename = "index.res"
let result = await sh`ls ${filename}`
```
```js
import * as $$Bun from "bun";
var filename = "index.res";
var result = await $$Bun.$`ls ${filename}`;
```
### Polymorphic Function
```res example
@module("Drawing") external drawCat: unit => unit = "draw"
@module("Drawing") external drawDog: (~giveName: string) => unit = "draw"
```
```js
// Empty output
```
```res example
@val
external padLeft: (
string,
@unwrap [
| #Str(string)
| #Int(int)
])
=> string = "padLeft"
padLeft("Hello World", #Int(4))
padLeft("Hello World", #Str("Message from ReScript: "))
```
```js
padLeft("Hello World", 4);
padLeft("Hello World", "Message from ReScript: ");
```
## JS Module Interop
[See here](import-from-export-to-js.md)
## Dangerous Type Cast
Final escape hatch converter. Do not abuse.
```res example
external convertToFloat: int => float = "%identity"
let age = 10
let gpa = 2.1 +. convertToFloat(age)
```
```js
var age = 10;
var gpa = 2.1 + 10;
```
---
title: "Interop with JS Build Systems"
description: "Documentation on how to interact with existing JS build systems"
canonical: "/docs/manual/v11.0.0/interop-with-js-build-systems"
---
# Interop with JS Build Systems
If you come from JS, chances are that you already have a build system in your existing project. Here's an overview of the role `rescript` would play in your build pipeline, if you want to introduce some ReScript code.
> **Please** try not to wrap `rescript` into your own incremental build framework. ReScript's compilation is very hard to get right, and you'll inevitably run into stale or badly performing builds (therefore erasing much of our value proposition) if you create your own meta layer on top.
## Popular JS Build Systems
The JS ecosystem uses a few build systems: [browserify](http://browserify.org/), [rollup](https://github.com/rollup/rollup), [webpack](https://webpack.js.org/), etc. The latter's probably the most popular of the three (as of 2019 =P). These build systems do both the compilation and the linking (aka, bundling many files into one or few files).
`rescript` only takes care of the compilation step; it maps one `.res`/`.resi` file into one JS output file. As such, in theory, no build system integration is needed from our side. From e.g. the webpack watcher's perspective, the JS files ReScript generates are almost equivalent to your hand-written JS files. We also recommend **that you initially check in those ReScript-generated JS files**, as this workflow means:
- You can introduce ReScript silently into your codebase without disturbing existing infra.
- You have a **visual** diff of the performance & correctness of your JS file when you update the `.res` files and the JS artifacts change.
- You can let teammates hot-patch the JS files in emergency situations, without needing to first start learning ReScript.
- You can remove ReScript completely from your codebase and things will still work (in case your company decides to stop using us for whatever reason).
For what it's worth, you can also turn `rescript` into an automated step in your build pipeline, e.g. into a Webpack loader; but such approach is error-prone and therefore discouraged.
### Tips & Tricks
You can make ReScript JS files look even more idiomatic through the in-source + bs suffix config in `rescript.json`:
```json
{
"package-specs": {
"module": "commonjs", // or whatever module system your project uses
"in-source": true
},
"suffix": ".res.js"
}
```
This will:
- Generate the JS files alongside your ReScript source files.
- Use the file extension `.res.js`, so that you can require these files on the JS side through `require('./MyFile.res.js')`, without needing a loader.
## Use Loaders on ReScript Side
"What if my build system uses a CSS/png/whatever loader and I'd like to use it in ReScript?"
Loaders are indeed troublesome; in the meantime, please use e.g. `%raw("require('./myStyles.css')")` at the top of your file. This just uses [`raw`](embed-raw-javascript.md) to compile the snippet into an actual JS require.
## Getting Project's Dependencies
`rescript` generates one `MyFile.d` file per `MyFile` source file; you'll find them in `lib/bs`. These are human readable, machine-friendly list of the dependencies of said `MyFile`. You can read into them for your purpose (though mind the IO overhead). Use these files instead of creating your own dependency graph; we did the hard work of tracking the dependencies as best as possible (including inner modules, `open`s, module names overlap, etc).
## Run Script Per File Built
See [js-post-build](build-configuration#js-post-build). Though please use it sparingly; if you hook up a node.js script after each file built, you'll incur the node startup time per file!
---
title: "Introduction"
description: "The hows and whys of ReScript"
canonical: "/docs/manual/v11.0.0/introduction"
---
# ReScript
Ever wanted a language like JavaScript, but without the warts, with a great type system, and with a lean build toolchain that doesn't waste your time?
ReScript looks like JS, acts like JS, and compiles to the highest quality of clean, readable and performant JS, directly runnable in browsers and Node.
**This means you can pick up ReScript and access the vast JavaScript ecosystem and tooling as if you've known ReScript for a long time!**
**ReScript is the language for folks who don't necessarily love JavaScript, but who still acknowledge its importance**.
## Difference vs TypeScript
We respect TypeScript very much and think that it's a positive force in the JavaScript ecosystem. ReScript shares some of the same goals as TypeScript, but is different enough regarding some important nuances:
- TypeScript's (admittedly noble) goal is to cover the entire JavaScript feature set and more. **ReScript covers only a curated subset of JavaScript**. For example, we emphasize plain data + functions over classes, clean [pattern matching](pattern-matching-destructuring.md) over fragile `if`s and virtual dispatches, [proper data modeling](variant.md) over string abuse, etc. JavaScript supersets will only grow larger over time; ReScript doesn't. \*
- Consequently, TypeScript's type system is necessarily complex, pitfalls-ridden, potentially requires tweaking, sometimes slow, and requires quite a bit of noisy annotations that often feel like manual bookkeeping rather than clear documentation. In contrast, ReScript's type system:
- Is deliberately curated to be a simple subset most folks will have an easier time to use.
- Has **no** pitfalls, aka the type system is "sound" (the types will always be correct). E.g. If a type isn't marked as nullable, its value will never lie and let through some `undefined` value silently. **ReScript code has no null/undefined errors**.
- Is the same for everyone. No knobs, no bikeshedding opportunity.
- Runs extremely fast precisely thanks to its simplicity and curation. It's one of the fastest compiler & build system toolchains for JavaScript development.
- **Doesn't need type annotations**. Annotate as much or as little as you'd like. The types are inferred by the language (and, again, are guaranteed correct).
- Migrating to TypeScript is done "breadth-first," whereas migrating to ReScript is done "depth-first." You can convert your codebase to TypeScript by "turning it on" for all files and annotate here and there; but how much type safety did you gain? How do you measure it? Type errors can still slip in and out of the converted pieces. For ReScript, our interop features draw clear boundaries: there's pure ReScript code, and there's JS interop code. Every piece of converted ReScript code is 100% clean. You'd convert file by file and each conversion increases your safety monotonically.
\* When you absolutely need to write or interoperate with free-for-all JavaScript, we expose enough escape hatches for you.
## Other Highlights
Aside from the aforementioned simple, robust and fast type system, ReScript presents a few more advantages.
### Faster than JavaScript
JavaScript's been aggressively optimized by talented engineers over a long span. Unfortunately, even for seasoned JS devs, it can be hard to know how to properly leverage JS's performance. ReScript's type system and compiler naturally guides you toward writing code that's very often performant by default, with good leverage of various Just-In-Time optimizations (hidden classes, inline caching, avoiding deopts, etc).
A widespread adage to write fast JavaScript code is to write as if there's a type system (in order to trigger JS engines' good optimization heuristics); ReScript gives you a real one and generates code that's friendly to optimizations by default.
### High Quality Dead Code Elimination
The JavaScript ecosystem is very reliant on dependencies. Shipping the final product inevitably drags in a huge amount of code, lots of which the project doesn't actually use. These regions of dead code impact loading, parsing and interpretation speed. ReScript provides powerful dead code elimination at all levels:
- Function- and module-level code elimination is facilitated by the well-engineered type system and purity analysis.
- At the global level, ReScript generates code that is naturally friendly to dead code elimination done by bundling tools such as [Rollup](https://github.com/rollup/rollup) and [Closure Compiler](https://developers.google.com/closure/compiler/), after its own sophisticated elimination pass.
- The same applies for ReScript's own tiny runtime (which is written in ReScript itself).
### Tiny JS Output
A `Hello world` ReScript program generates **20 bytes** of JS code. Additionally, the standard library pieces you require in are only included when needed.
### Fast Iteration Loop
ReScript's build time is **one or two orders of magnitude** faster than alternatives. In its watcher mode, the build system usually finishes before you switch screen from the editor to the terminal tab (two digits of milliseconds). A fast iteration cycle reduces the need of keeping one's mental state around longer; this in turn allows one to stay in the flow longer and more often.
### Readable Output & Great Interop
Unreadable JavaScript code generated from other compiled-to-js languages makes it so that it could be, practically speaking:
- Hard to debug (cryptic stack trace, mangled variable names)
- Hard to learn from (non-straightforward mapping of concepts from one language to another)
- Hard to profile for performance (unclear what runtime performance cost there is)
- Hard to integrate with existing hand-written JS code
ReScript's JS output is very readable. This is especially important while learning, where users might want to understand how the code's compiled, and to audit for bugs.
This characteristic, combined with a fully-featured JS interop system, allows ReScript code to be inserted into an existing JavaScript codebase almost unnoticed.
### Preservation of Code Structure
ReScript maps one source file to one JavaScript output file. This eases the integration of existing tools such as bundlers and test runners. You can even start writing a single file without much change to your build setup. Each file's code structure is approximately preserved, too.
## Conclusion
We hope the above gave you enough of an idea of ReScript and its differentiators. Feel free to [try it online](/try) to get a feel!
---
title: "JSON"
description: "Interacting with JSON in ReScript"
canonical: "/docs/manual/v11.0.0/json"
---
# JSON
## Parse
Bind to JavaScript's `JSON.parse` and type the return value as the type you're expecting:
```res example
// declare the shape of the json you're binding to
type data = {names: array}
// bind to JS' JSON.parse
@scope("JSON") @val
external parseIntoMyData: string => data = "parse"
let result = parseIntoMyData(`{"names": ["Luke", "Christine"]}`)
let name1 = result.names[0]
```
```js
var result = JSON.parse("{\"names\": [\"Luke\", \"Christine\"]}");
var name1 = result.names[0];
```
Where `data` can be any type you assume the JSON is. As you can see, this compiles to a straightforward `JSON.parse` call. As with regular JS, this is convenient, but has no guarantee that e.g. the data is correctly shaped, or even syntactically valid. Slightly dangerous.
## Stringify
Use [`JSON.stringify`](api/core/json#value-stringify) if your data is of type `JSON.t` or [`JSON.stringifyAny`](api/core/json#value-stringifyAny) if it is not.
```res example
Console.log(JSON.stringifyAny(["Amy", "Joe"]))
```
```js
console.log(JSON.stringify([
"Amy",
"Joe"
]));
```
## Import a JSON file
Use the `@module` attribute to import JSON files directly.
```res example
@module external studentNames: JSON.t = "./students.json"
Console.log(studentNames)
```
```js
import * as StudentsJson from "./students.json";
var studentNames = StudentsJson;
console.log(studentNames);
```
```js
var StudentsJson = require("./students.json");
var studentNames = StudentsJson;
console.log(studentNames);
```
## Advanced
Thanks to untagged variants, JSON can be encoded and decoded idiomatically. Check it out on [the variants page](variant#decoding-and-encoding-json-idiomatically).
---
title: "JSX"
description: "JSX syntax in ReScript and React"
canonical: "/docs/manual/v11.0.0/jsx"
---
# JSX
Would you like some HTML syntax in your ReScript? If not, quickly skip over this section and pretend you didn't see anything!
ReScript supports the JSX syntax, with some slight differences compared to the one in [ReactJS](https://facebook.github.io/react/docs/introducing-jsx.html). ReScript JSX isn't tied to ReactJS; they translate to normal function calls:
**Note** for [ReScriptReact](https://rescript-lang.org/docs/react/latest/introduction) readers: this isn't what ReScriptReact turns JSX into, in the end. See Usage section for more info.
## Capitalized
```res
```
```js
React.createElement(MyComponent, {
name: "ReScript",
});
```
becomes
```res
MyComponent.createElement(~name="ReScript", ~children=list{}, ())
```
```js
React.createElement(MyComponent, {
name: "ReScript",
});
```
## Uncapitalized
```res
child1 child2
```
```js
React.createElement("div", {
onClick: handler
}, child1, child2);
```
becomes
```res
div(~onClick=handler, ~children=list{child1, child2}, ())
```
```js
React.createElement("div", {
onClick: handler
}, child1, child2);
```
## Fragment
```res
<> child1 child2 >
```
```js
React.createElement(React.Fragment, undefined, child1, child2);
```
becomes
```res
list{child1, child2}
```
```js
React.createElement(React.Fragment, undefined, child1, child2);
```
### Children
```res
child1 child2
```
```js
React.createElement(MyComponent, { children: null }, child1, child2);
```
This is the syntax for passing a list of two items, `child1` and `child2`, to the children position. It transforms to a list containing `child1` and `child2`:
```res
MyComponent.createElement(~children=list{child1, child2}, ())
```
```js
React.createElement(MyComponent.make, MyComponent.makeProps(null, undefined), child1, child2);
```
**Note** again that this isn't the transform for ReScriptReact; ReScriptReact turns the final list into an array. But the idea still applies.
So naturally, ` myChild ` is transformed to `MyComponent.createElement(~children=list{myChild}, ())`. I.e. whatever you do, the arguments passed to the children position will be wrapped in a list.
## Usage
See [ReScriptReact Elements & JSX](https://rescript-lang.org/docs/react/latest/elements-and-jsx) for an example application of JSX, which transforms the above calls into a ReScriptReact-specific call.
Here's a JSX tag that shows most of the features.
```res
{React.string("hello")}
```
```js
React.createElement(MyComponent, {
children: React.createElement("div", undefined, "hello"),
booleanAttribute: true,
stringAttribute: "string",
intAttribute: 1,
forcedOptional: "hello",
onClick: handleClick
});
```
## Departures From JS JSX
- Attributes and children don't mandate `{}`, but we show them anyway for ease of learning. Once you format your file, some of them go away and some turn into parentheses.
- Props spread is supported, but there are some restrictions (see below).
- Punning!
- Props and tag names have to follow ReScript's restrictions on identifiers at the exception of hyphens for lowercase tags ([see below](#hyphens-in-tag-names)).
### Spread Props
**Since 10.1**
JSX props spread is supported now, but in a stricter way than in JS.
```res
```
```js
React.createElement(Comp, {
a: "a",
b: "b"
});
```
Multiple spreads are not allowed:
```res
```
The spread must be at the first position, followed by other props:
```res
```
### Punning
"Punning" refers to the syntax shorthand for when a label and a value are the same. For example, in JavaScript, instead of doing `return {name: name}`, you can do `return {name}`.
JSX supports punning. `` is just a shorthand for ``. The formatter will help you format to the punned syntax whenever possible. This is convenient in the cases where there are lots of props to pass down:
```res
```
```js
React.createElement(MyComponent, {
isLoading: true,
text: text,
onClick: onClick
});
```
Consequently, a JSX component can cram in a few more props before reaching for extra libraries solutions that avoids props passing.
**Note** that this is a departure from ReactJS JSX, which does **not** have punning. ReactJS' `` desugars to ``, in order to conform to DOM's idioms and for backward compatibility.
### Hyphens in tag names
**Since 11.1**
JSX now supports lowercase tags with hyphens in their name. This allows to bind
to web components.
Note though that props names can't have hyphens, you should use `@as` to bind to
such props in your custom `JsxDOM.domProps` type ([see generic JSX transform](#generic-jsx-transform-jsx-beyond-react-experimental)).
```res
```
```js
React.createElement("model-viewer", {
"touch-actions": "pan-y",
src: src
});
```
## Generic JSX transform: JSX beyond React (experimental)
**Since 11.1**
While ReScript comes with first class support for JSX in React, it's also possible to have ReScript delegate JSX to other frameworks. You do that by configuring a _generic JSX transform_.
This is what you need to do to use a generic JSX transform:
1. Make sure you have a ReScript module that [implements the functions and types necessary for the JSX transform](#implementing-a-generic-jsx-transform-module).
2. Configure `rescript.json` to delegated JSX to that module.
That's it really. We'll expand on each point below.
### Configuration
You configure a generic JSX transform by putting any module name in the `module` config of JSX in `rescript.json`. This can be _any valid module name_. Example part from `rescript.json`:
```json
"jsx": {
"module": "Preact"
},
```
This will now put the `Preact` module in control of the generated JSX calls. The `Preact` module can be defined by anyone - locally in your project, or by a package. As long a it's available in the global scope. The JSX transform will delegate any JSX related code to `Preact`.
#### What about `@react.component` for components?
`@react.component` will still be available, and so is a generic `@jsx.component` notation. Both work the same way.
### Usage Example
Here's a quick usage example (the actual definition of `Preact.res` comes below):
First, configure `rescript.json`:
```json
"jsx": {
"module": "Preact"
},
```
Now you can build Preact components:
```rescript
// Name.res
@jsx.component // or @react.component if you want
let make = (~name) => Preact.string(`Hello ${name}!`)
```
And you can use them just like normal with JSX:
```rescript
let name =
```
#### File level configuration
You can configure what JSX transform is used at the file level via `@@jsxConfig`, just like before. Like:
```rescript
@@jsxConfig({module_: "Preact"})
```
This can be convenient if you're mixing different JSX frameworks in the same project.
### Implementing a generic JSX transform module
Below is a full list of everything you need in a generic JSX transform module, including code comments to clarify. It's an example implementation of a `Preact` transform, so when doing this for other frameworks you'd of course adapt what you import from, and so on.
> You can easily copy-paste-and-adapt this to your needs if you're creating bindings to a JSX framework. Most often, all you'll need to change is what the `@module("") external` points to, so the runtime calls point to the correct JS module.
```rescript
// Preact.res
/* Below is a number of aliases to the common `Jsx` module */
type element = Jsx.element
type component<'props> = Jsx.component<'props>
type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return>
@module("preact")
external jsx: (component<'props>, 'props) => element = "jsx"
@module("preact")
external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx"
@module("preact")
external jsxs: (component<'props>, 'props) => element = "jsxs"
@module("preact")
external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs"
/* These identity functions and static values below are optional, but lets
you move things easily to the `element` type. The only required thing to
define though is `array`, which the JSX transform will output. */
external array: array => element = "%identity"
@val external null: element = "null"
external float: float => element = "%identity"
external int: int => element = "%identity"
external string: string => element = "%identity"
/* These are needed for Fragment (<> >) support */
type fragmentProps = {children?: element}
@module("preact") external jsxFragment: component = "Fragment"
/* The Elements module is the equivalent to the ReactDOM module in React. This holds things relevant to _lowercase_ JSX elements. */
module Elements = {
/* Here you can control what props lowercase JSX elements should have.
A base that the React JSX transform uses is provided via JsxDOM.domProps,
but you can make this anything. The editor tooling will support
autocompletion etc for your specific type. */
type props = JsxDOM.domProps
@module("preact")
external jsx: (string, props) => Jsx.element = "jsx"
@module("preact")
external div: (string, props) => Jsx.element = "jsx"
@module("preact")
external jsxKeyed: (string, props, ~key: string=?, @ignore unit) => Jsx.element = "jsx"
@module("preact")
external jsxs: (string, props) => Jsx.element = "jsxs"
@module("preact")
external jsxsKeyed: (string, props, ~key: string=?, @ignore unit) => Jsx.element = "jsxs"
external someElement: element => option = "%identity"
}
```
As you can see, most of the things you'll want to implement will be copy paste from the above. But do note that **everything needs to be there unless explicitly noted** or the transform will fail at compile time.
---
title: "Lazy Value"
description: "Data type for deferred computation in ReScript"
canonical: "/docs/manual/v11.0.0/lazy-values"
---
# Lazy Value
If you have some expensive computations you'd like to **defer and cache** subsequently, you can wrap it with `lazy`:
```res prelude
@module("node:fs")
external readdirSync: string => array = "readdirSync"
// Read the directory, only once
let expensiveFilesRead = lazy({
Console.log("Reading dir")
readdirSync("./pages")
})
```
```js
var Fs = require("fs");
var expensiveFilesRead = {
LAZY_DONE: false,
VAL: (function () {
console.log("Reading dir");
return Fs.readdirSync("./pages");
})
};
```
Check the JS Output tab: that `expensiveFilesRead`'s code isn't executed yet, even though you declared it! You can carry it around without fearing that it'll run the directory read.
**Note**: a lazy value is **not** a [shared data type](shared-data-types.md). Don't rely on its runtime representation in your JavaScript code.
## Execute The Lazy Computation
To actually run the lazy value's computation, use `Lazy.force` from the globally available `Lazy` module:
```res example
// First call. The computation happens
Console.log(Lazy.force(expensiveFilesRead)) // logs "Reading dir" and the directory content
// Second call. Will just return the already calculated result
Console.log(Lazy.force(expensiveFilesRead)) // logs the directory content
```
```js
console.log(CamlinternalLazy.force(expensiveFilesRead));
console.log(CamlinternalLazy.force(expensiveFilesRead));
```
The first time `Lazy.force` is called, the expensive computation happens and the result is **cached**. The second time, the cached value is directly used.
**You can't re-trigger the computation after the first `force` call**. Make sure you only use a lazy value with computations whose results don't change (e.g. an expensive server request whose response is always the same).
Instead of using `Lazy.force`, you can also use [pattern matching](pattern-matching-destructuring.md) to trigger the computation:
```res example
switch expensiveFilesRead {
| lazy(result) => Console.log(result)
}
```
```js
var result = CamlinternalLazy.force(expensiveFilesRead);
```
Since pattern matching also works on a `let` binding, you can also do:
```res example
let lazy(result) = expensiveFilesRead
Console.log(result)
```
```js
var result = CamlinternalLazy.force(expensiveFilesRead);
console.log(result);
```
## Exception Handling
For completeness' sake, our files read example might raise an exception because of `readdirSync`. Here's how you'd handle it:
```res example
let result = try {
Lazy.force(expensiveFilesRead)
} catch {
| Not_found => [] // empty array of files
}
```
```js
var result;
try {
result = CamlinternalLazy.force(expensiveFilesRead);
} catch (raw_exn) {
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === "Not_found") {
result = [];
} else {
throw exn;
}
}
```
Though you should probably handle the exception inside the lazy computation itself.
---
title: "Let Binding"
description: "Let binding syntax for binding to values in ReScript"
canonical: "/docs/manual/v11.0.0/let-binding"
---
# Let Binding
A "let binding", in other languages, might be called a "variable declaration". `let` _binds_ values to names. They can be seen and referenced by code that comes _after_ them.
```res example
let greeting = "hello!"
let score = 10
let newScore = 10 + score
```
```js
var greeting = "hello!";
var score = 10;
var newScore = 20;
```
## Block Scope
Bindings can be scoped through `{}`.
```res example
let message = {
let part1 = "hello"
let part2 = "world"
part1 ++ " " ++ part2
}
// `part1` and `part2` not accessible here!
```
```js
var message = "hello world";
```
The value of the last line of a scope is implicitly returned.
### Design Decisions
ReScript's `if`, `while` and functions all use the same block scoping mechanism. The code below works **not** because of some special "if scope"; but simply because it's the same scope syntax and feature you just saw:
```res
if displayGreeting {
let message = "Enjoying the docs so far?"
Console.log(message)
}
// `message` not accessible here!
```
```js
if (displayGreeting) {
console.log("Enjoying the docs so far?");
}
```
## Bindings Are Immutable
Let bindings are "immutable", aka "cannot change". This helps our type system deduce and optimize much more than other languages (and in turn, help you more).
## Binding Shadowing
The above restriction might sound unpractical at first. How would you change a value then? Usually, 2 ways:
The first is to realize that many times, what you want isn't to mutate a variable's value. For example, this JavaScript pattern:
```js
var result = 0;
result = calculate(result);
result = calculateSomeMore(result);
```
...is really just to comment on intermediate steps. You didn't need to mutate `result` at all! You could have just written this JS:
```js
var result1 = 0;
var result2 = calculate(result1);
var result3 = calculateSomeMore(result2);
```
In ReScript, this obviously works too:
```res
let result1 = 0
let result2 = calculate(result1)
let result3 = calculateSomeMore(result2)
```
```js
var result1 = 0;
var result2 = calculate(0);
var result3 = calculateSomeMore(result2);
```
Additionally, reusing the same let binding name overshadows the previous bindings with the same name. So you can write this too:
```res
let result = 0
let result = calculate(result)
let result = calculateSomeMore(result)
```
```js
var result = calculate(0);
var result$1 = calculateSomeMore(result);
```
(Though for the sake of clarity, we don't recommend this).
As a matter of fact, even this is valid code:
```res example
let result = "hello"
Console.log(result) // prints "hello"
let result = 1
Console.log(result) // prints 1
```
```js
var result = 1;
console.log("hello");
console.log(1);
```
The binding you refer to is whatever's the closest upward. No mutation here!
If you need _real_ mutation, e.g. passing a value around, have it modified by many pieces of code, we provide a slightly heavier [mutation feature](mutation.md).
## Private let bindings
Private let bindings are introduced in the release [7.2](https://rescript-lang.org/blog/bucklescript-release-7-2).
In the module system, everything is public by default,
the only way to hide some values is by providing a separate signature to
list public fields and their types:
```res
module A: {
let b: int
} = {
let a = 3
let b = 4
}
```
`%%private` gives you an option to mark private fields directly
```res
module A = {
%%private(let a = 3)
let b = 4
}
```
`%%private` also applies to file level modules, so in some cases,
users do not need to provide a separate interface file just to hide some particular values.
Note interface files are still recommended as a general best practice since they give you better
separate compilation units and also they're better for documentation.
Still, `%%private` is useful in the following scenarios:
- **Code generators.** Some code generators want to hide some values but it is sometimes very hard or time consuming for code generators to synthesize the types for public fields.
- **Quick prototyping.** During prototyping, we still want to hide some values, but the interface file is not stable yet. `%%private` provides you such convenience.
---
title: "Libraries & Publishing"
description: "Install & publish ReScript packages"
canonical: "/docs/manual/v11.0.0/libraries"
---
# Libraries & Publishing
ReScript libraries are just like JavaScript libraries: published & hosted on [NPM](http://npmjs.com). You can reuse your `npm`, `yarn` and `package.json`-related tools to manage them!
## Tips & Tricks
### Publish
We recommend you to check in your compiled JavaScript output, for its [various benefits](interop-with-js-build-systems.md#popular-js-build-systems). If not, then at least consider publishing the JavaScript output by un-ignoring them in your [npmignore](https://docs.npmjs.com/cli/v7/using-npm/developers#keeping-files-out-of-your-package). This way, your published ReScript package comes with plain JavaScript files that JS users can consume. If your project's good, JS users might not even realize that they've installed a library written in ReScript!
In case your library is only consumed by JS users, you may want to check out our [external stdlib](./build-external-stdlib) configuration as well.
### Find Libraries
Search `rescript`-related packages on NPM, or use our [Package Index](/packages).
If you can't find what you're looking for, remember that **you don't need a wrapper** to use a JS library:
- Most JS data types, such as array and objects, [map over cleanly to ReScript and vice-versa](shared-data-types.md).
- You also have access to the familiar [Core API](api/core).
- You can use a JavaScript library without needing to install dedicated binding libraries. Check the [`external`](external) page.
---
title: "LLMs"
description: "Documentation for LLMs"
canonical: "/docs/manual/v11.0.0/llms"
---
# Documentation for LLMs
We adhere to the [llms.txt convention](https://llmstxt.org/) to make documentation accessible to large language models and their applications.
Currently, we have the following files...
- [/docs/manual/llms.txt](/llms/manual/v11.0.0/llms.txt) — a list of the available files for ReScript language.
- [/docs/manual/llm-full.txt](/llms/manual/v11.0.0/llm-full.txt) — complete documentation for ReScript language.
- [/docs/manual/llm-small.txt](/llms/manual/v11.0.0/llm-small.txt) — compressed version of the former, without examples.
...and package-level documentation:
- [/docs/react/llms](/docs/react/latest/llms) — the LLms documentation for ReScript React.
## Notes
- The content is automatically generated from the same source as the official documentation for the specific version
---
title: "Migrate to v11"
description: "Instructions on upgrading to ReScript 11"
canonical: "/docs/manual/v11.0.0/migrate-to-v11"
---
# Migrate to ReScript 11
## Foreword
The ReScript community is proud to introduce ReScript V11 which comes with a ton of new features but also removes a lot of bulk.
A migration to it can be very straightforward, but it can also take some time, depending on your code style or what dependencies you use.
Please have a look at the full [set of breaking changes](#list-of-all-breaking-changes) below to be able to decide whether this is a task you want to undertake. There is also the possibilty to [opt-out of uncurried mode](#minimal-migration) for now, which is probably the most fundamental change of this release. That and other new and notable features are discussed in the following blogposts:
- [Better interop with customizable variants](/blog/improving-interop)
- [Enhanced Ergonomics for Record Types](/blog/enhanced-ergonomics-for-record-types)
- [First-class Dynamic Import Support](/blog/first-class-dynamic-import-support)
- [Uncurried Mode](/blog/uncurried-mode)
## Recommended Migration
### Uncurried Mode
For uncurried mode to take effect in ReScript 11 there is nothing to configure, it is activated by default.
### Adapt suffix
ReScript 11 now allows having arbitrary suffixes in the generated JavaScript files. However, it is still recommended to stick to using `.res.js`, `.res.mjs` or `.res.cjs`. For more information, read the Build System Configuration about [suffixes](/docs/manual/latest/build-configuration#suffix).
### rescript.json
The old configuration filename `bsconfig.json` is deprecated. Rename `bsconfig.json` to `rescript.json` to get rid of the deprecation warning.
### ReScript Core standard library
[ReScript Core](https://github.com/rescript-lang/rescript-core) is ReScript's new standard library. It replaces the complete `Js` module as well as some of the more frequently used modules from `Belt` and is recommended to use with uncurried mode.
It will be integrated into the compiler in a future version. In ReScript 11, it still needs to be installed manually:
```console
$ npm install @rescript/core
```
Then add `@rescript/core` to your `rescript.json`'s dependencies:
```diff
{
"bs-dependencies": [
+ "@rescript/core"
]
}
```
Open it so it's available in the global scope.
```diff
{
"bsc-flags": [
+ "-open RescriptCore",
]
}
```
One major change to be aware of is that array access now returns an `option`.
```res
let firstItem = myArray[0] // Some("hello")
```
If you would like to not use an `option`, you can use [`Array.getUnsafe`](api/core/array#value-getUnsafe).
For a detailed explanation on migration to ReScript Core, please refer to its [migration guide](https://github.com/rescript-lang/rescript-core#migration). A semi-automated script is available as well.
See ReScript Core API docs [here](api/core).
### Removed bindings
Many Node bindings have been removed from the compiler. Please use [rescript-nodejs](https://github.com/TheSpyder/rescript-nodejs) instead or write your own local bindings.
## Minimal Migration
This guide describes the things to do at least to migrate to ReScript 11.
### Disable uncurried mode
If you use currying extensively and don't want to bother with adapting your code, or have dependencies that just don't work with uncurried mode yet, just set it to false in your `rescript.json`.
```json
{
"uncurried": false
}
```
For more information, read the Build System Configuration about [uncurried](/docs/manual/latest/build-configuration#uncurried).
## List of all breaking changes
Below is an excerpt from the compiler changelog about all the breaking changes of ReScript 11.
### Language and Compiler
- Add smart printer for pipe chains. https://github.com/rescript-lang/rescript/pull/6411 (the formatter will reformat existing code in certain cases)
- Parse `assert` as a regular function. `assert` is no longer a unary expression. Example: before `assert 1 == 2` is parsed as `(assert 1) == 2`, now it is parsed as `assert(1 == 2)`. https://github.com/rescript-lang/rescript/pull/6180
- Remove support for the legacy Reason syntax. Existing Reason code can be converted to ReScript syntax using ReScript 9 as follows:
- `npx rescript@9 convert `
- Curried after uncurried is not fused anymore: `(. x) => y => 3` is not equivalent to `(. x, y) => 3` anymore. It's instead equivalent to `(. x) => { y => 3 }`.
Also, `(. int) => string => bool` is not equivalen to `(. int, string) => bool` anymore.
These are only breaking changes for unformatted code.
- Exponentiation operator `**` is now right-associative. `2. ** 3. ** 2.` now compile to `Math.pow(2, Math.pow(3, 2))` and not anymore `Math.pow(Math.pow(2, 3), 2)`. Parentheses can be used to change precedence.
- Stop mangling object field names. If you had objects with field names containing "\__" or leading "_", they won't be mangled in the compiled JavaScript and represented as it is without changes. https://github.com/rescript-lang/rescript/pull/6354
- `$$default` is no longer exported from the generated JavaScript when using default exports. https://github.com/rescript-lang/rescript/pull/6328
- `-bs-super-errors` flag has been deprecated along with Super_errors. https://github.com/rescript-lang/rescript/pull/6243
- Remove unsafe `` j`$(a)$(b)` `` interpolation deprecated in compiler version 10 https://github.com/rescript-lang/rescript/pull/6068
- `@deriving(jsConverter)` not supported anymore for variant types https://github.com/rescript-lang/rescript/pull/6088
- New representation for variants, where the tag is a string instead of a number. https://github.com/rescript-lang/rescript/pull/6088
### Compiler Libraries
- Fixed name collision between the newly defined Js.Json.t and the variant constructor in the existing Js.Json.kind type. To address this, the usage of the existing Js.Json.kind type can be updated to Js.Json.Kind.t. https://github.com/rescript-lang/rescript/pull/6317
- Remove rudimentary node bindings and undocumented `%node` extension. https://github.com/rescript-lang/rescript/pull/6285
- `@rescript/react` >= 0.12.0-alpha.2 is now required because of the React.fragment's children type fix. https://github.com/rescript-lang/rescript/pull/6238
- Remove deprecated module `Printexc`
### Build System and Tools
- Update watcher rules to recompile only on config and `*.res`/`*.resi`/`*.ml`/`.mli` file changes. Solves the issue of unnecessary recompiles on `.css`, `.ts`, and other unrelated file changes. https://github.com/rescript-lang/rescript/pull/6420
- Made pinned dependencies transitive: if _a_ is a pinned dependency of _b_ and _b_ is a pinned dependency of _c_, then _a_ is implicitly a pinned dependency of _c_. This change is only breaking if your build process assumes non-transitivity.
- Remove obsolete built-in project templates and the "rescript init" functionality. This is replaced by [create-rescript-app](https://github.com/rescript-lang/create-rescript-app) which is maintained separately.
- Do not attempt to build ReScript from source on npm postinstall for platforms without prebuilt binaries anymore.
- GenType: removed support for `@genType.as` for records and variants which has become unnecessary. Use the language's `@as` instead to channge the runtime representation without requiring any runtime conversion during FFI. https://github.com/rescript-lang/rescript/pull/6099 https://github.com/rescript-lang/rescript/pull/6101
---
title: "Module Functions"
description: "Module Functions in ReScript"
canonical: "/docs/manual/v11.0.0/module-functions"
---
# Module Functions
Module functions can be used to create modules based on types, values, or functions from other modules.
This is a powerful tool that can be used to create abstractions and reusable code that might not be possible with functions, or might have a runtime cost if done with functions.
This is an advanced part of ReScript and you can generally get by with normal values and functions.
## Quick example
Next.js has a `useParams` hook that returns an unknown type,
and it's up to the developer in TypeScript to add a type annotation for the parameters returned by the hook.
```TS
const params = useParams<{ tag: string; item: string }>()
```
In ReScript we can create a module function that will return a typed response for the `useParams` hook.
```res example
module Next = {
// define our module function
module MakeParams = (Params: { type t }) => {
@module("next/navigation")
external useParams: unit => Params.t = "useParams"
/* You can use values from the function parameter, such as Params.t */
}
}
module Component: {
@react.component
let make: unit => Jsx.element
} = {
// Create a module that matches the module type expected by Next.MakeParams
module P = {
type t = {
tag: string,
item: string,
}
}
// Create a new module using the Params module we created and the Next.MakeParams module function
module Params = Next.MakeParams(P)
@react.component
let make = () => {
// Use the functions, values, or types created by the module function
let params = Params.useParams()
{React.string("Tag: " ++ params.tag /* params is fully typed! */)}
{React.string("Item: " ++ params.item)}
}
}
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE
import * as $$Navigation from "next/navigation";
import * as JsxRuntime from "react/jsx-runtime";
function MakeParams(Params) {
return {};
}
var Next = {
MakeParams: MakeParams
};
function Playground$Component(props) {
var params = $$Navigation.useParams();
return JsxRuntime.jsxs("div", {
children: [
JsxRuntime.jsx("p", {
children: "Tag: " + params.tag
}),
JsxRuntime.jsx("p", {
children: "Item: " + params.item
})
]
});
}
var Component = {
make: Playground$Component
};
export {
Next ,
Component ,
}
/* next/navigation Not a pure module */
```
CodeTab>
## Sharing a type with an external binding
This becomes incredibly useful when you need to have types that are unique to a project but shared across multiple components.
Let's say you want to create a library with a `getEnv` function to load in environment variables found in `import.meta.env`.
```res
@val external env: 'a = "import.meta.env"
let getEnv = () => {
env
}
```
It's not possible to define types for this that will work for every project, so we just set it as 'a and the consumer of our library can define the return type.
```res
type t = {"LOG_LEVEL": string}
let values: t = getEnv()
```
This isn't great and it doesn't take advantage of ReScript's type system and ability to use types without type definitions, and it can't be easily shared across our application.
We can instead create a module function that can return a module that has contains a `getEnv` function that has a typed response.
```res
module MakeEnv = (
E: {
type t
},
) => {
@val external env: E.t = "import.meta.env"
let getEnv = () => {
env
}
}
```
And now consumers of our library can define the types and create a custom version of the hook for their application.
Notice that in the JavaScript output that the `import.meta.env` is used directly and doesn't require any function calls or runtime overhead.
```res
module Env = MakeEnv({
type t = {"LOG_LEVEL": string}
})
let values = Env.getEnv()
```
```js
var Env = {
getEnv: getEnv
};
var values = import.meta.env;
```
CodeTab>
## Shared functions
You might want to share functions across modules, like a way to log a value or render it in React.
Here's an example of module function that takes in a type and a transform to string function.
```res
module MakeDataModule = (
T: {
type t
let toString: t => string
},
) => {
type t = T.t
let log = a => Console.log("The value is " ++ T.toString(a))
module Render = {
@react.component
let make = (~value) => value->T.toString->React.string
}
}
```
You can now take a module with a type of `t` and a `toString` function and create a new module that has the `log` function and the `Render` component.
```res
module Person = {
type t = { firstName: string, lastName: string }
let toString = person => person.firstName ++ person.lastName
}
module PersonData = MakeDataModule(Person)
```
```js
// Notice that none of the JS output references the MakeDataModule function
function toString(person) {
return person.firstName + person.lastName;
}
var Person = {
toString: toString
};
function log(a) {
console.log("The value is " + toString(a));
}
function Person$MakeDataModule$Render(props) {
return toString(props.value);
}
var Render = {
make: Person$MakeDataModule$Render
};
var PersonData = {
log: log,
Render: Render
};
```
Now the `PersonData` module has the functions from the `MakeDataModule`.
```res
@react.component
let make = (~person) => {
let handleClick = _ => PersonData.log(person)
{React.string("Hello ")}
}
```
```js
function Person$1(props) {
var person = props.person;
var handleClick = function (param) {
log(person);
};
return JsxRuntime.jsxs("div", {
children: [
"Hello ",
JsxRuntime.jsx(Person$MakeDataModule$Render, {
value: person
}),
JsxRuntime.jsx("button", {
children: "Log value to console",
onClick: handleClick
})
]
});
}
```
## Dependency injection
Module functions can be used for dependency injection.
Here's an example of injecting in some config values into a set of functions to access a database.
```res
module type DbConfig = {
let host: string
let database: string
let username: string
let password: string
}
module MakeDbConnection = (Config: DbConfig) => {
type client = {
write: string => unit,
read: string => string,
}
@module("database.js")
external makeClient: (string, string, string, string) => client = "makeClient"
let client = makeClient(Config.host, Config.database, Config.username, Config.password)
}
module Db = MakeDbConnection({
let host = "localhost"
let database = "mydb"
let username = "root"
let password = "password"
})
let updateDb = Db.client.write("new value")
```
```js
// Generated by ReScript, PLEASE EDIT WITH CARE
import * as DatabaseJs from "database.js";
function MakeDbConnection(Config) {
var client = DatabaseJs.makeClient(Config.host, Config.database, Config.username, Config.password);
return {
client: client
};
}
var client = DatabaseJs.makeClient("localhost", "mydb", "root", "password");
var Db = {
client: client
};
var updateDb = client.write("new value");
export {
MakeDbConnection ,
Db ,
updateDb ,
}
/* client Not a pure module */
```
---
title: "Module"
description: "ReScript modules, module signatures and interface files"
canonical: "/docs/manual/v11.0.0/module"
---
# Module
## Basics
**Modules are like mini files**! They can contain type definitions, `let`
bindings, nested modules, etc.
### Creation
To create a module, use the `module` keyword. The module name must start with a
**capital letter**. Whatever you could place in a `.res` file, you may place
inside a module definition's `{}` block.
```res example
module School = {
type profession = Teacher | Director
let person1 = Teacher
let getProfession = (person) =>
switch person {
| Teacher => "A teacher"
| Director => "A director"
}
}
```
```js
function getProfession(person) {
if (person) {
return "A director";
} else {
return "A teacher";
}
}
var School = {
person1: /* Teacher */0,
getProfession: getProfession
};
```
A module's contents (including types!) can be accessed much like a record's,
using the `.` notation. This demonstrates modules' utility for namespacing.
```res
let anotherPerson: School.profession = School.Teacher
Console.log(School.getProfession(anotherPerson)) /* "A teacher" */
```
```js
var anotherPerson = /* Teacher */0;
console.log("A teacher");
```
Nested modules work too.
```res example
module MyModule = {
module NestedModule = {
let message = "hello"
}
}
let message = MyModule.NestedModule.message
```
```js
var NestedModule = {
message: message
};
var MyModule = {
NestedModule: NestedModule
};
var message = MyModule.NestedModule.message;
```
### `open`ing a module
Constantly referring to a value/type in a module can be tedious. Instead, we can "open" a module and refer to its contents without always prepending them with the
module's name. Instead of writing:
```res
let p = School.getProfession(School.person1)
```
```js
var p = School.getProfession(School.person1);
```
We can write:
```res
open School
let p = getProfession(person1)
```
```js
var p = School.getProfession(School.person1);
```
The content of `School` module are made visible (**not** copied into the file, but simply made visible!) in scope. `profession`, `getProfession` and `person1` will thus correctly be found.
**Use `open` this sparingly, it's convenient, but makes it hard to know where some values come from**. You should usually use `open` in a local scope:
```res
let p = {
open School
getProfession(person1)
}
/* School's content isn't visible here anymore */
```
```js
var p = School.getProfession(School.person1);
```
### Use `open!` to ignore shadow warnings
There are situations where `open` will cause a warning due to existing identifiers (bindings, types) being redefined. Use `open!` to explicitly tell the compiler that this is desired behavior.
```res
let map = (arr, value) => {
value
}
// opening Array would shadow our previously defined `map`
// `open!` will explicitly turn off the automatic warning
open! Array
let arr = map([1,2,3], (a) => { a + 1})
```
**Note:** Same as with `open`, don't overuse `open!` statements if not necessary. Use (sub)modules to prevent shadowing issues.
### Destructuring modules
**Since 9.0.2**
As an alternative to `open`ing a module, you can also destructure a module's functions and values into separate let bindings (similarly on how we'd destructure an object in JavaScript).
```res
module User = {
let user1 = "Anna"
let user2 = "Franz"
}
// Destructure by name
let {user1, user2} = module(User)
// Destructure with different alias
let {user1: anna, user2: franz} = module(User)
```
```js
var user1 = "Anna";
var user2 = "Franz";
var User = {
user1: user1,
user2: user2
};
```
**Note:** You can't extract types with module destructuring — use a type alias instead (`type user = User.myUserType`).
### Extending modules
Using `include` in a module statically "spreads" a module's content into a new one, thus often fulfill the role of "inheritance" or "mixin".
**Note**: this is equivalent to a compiler-level copy paste. **We heavily discourage `include`**. Use it as last resort!
```res example
module BaseComponent = {
let defaultGreeting = "Hello"
let getAudience = (~excited) => excited ? "world!" : "world"
}
module ActualComponent = {
/* the content is copied over */
include BaseComponent
/* overrides BaseComponent.defaultGreeting */
let defaultGreeting = "Hey"
let render = () => defaultGreeting ++ " " ++ getAudience(~excited=true)
}
```
```js
function getAudience(excited) {
if (excited) {
return "world!";
} else {
return "world";
}
}
var BaseComponent = {
defaultGreeting: "Hello",
getAudience: getAudience
};
var defaultGreeting = "Hey";
function render(param) {
return "Hey world!";
}
var ActualComponent = {
getAudience: getAudience,
defaultGreeting: defaultGreeting,
render: render
};
```
**Note**: `open` and `include` are very different! The former brings a module's content into your current scope, so that you don't have to refer to a value by prefixing it with the module's name every time. The latter **copies over** the definition of a module statically, then also do an `open`.
### Every `.res` file is a module
Every ReScript file is itself compiled to a module of the same name as the file name, capitalized. The file `React.res` implicitly forms a module `React`, which can be seen by other source files.
**Note**: ReScript file names should, by convention, be capitalized so that their casing matches their module name. Uncapitalized file names are not invalid, but will be implicitly transformed into a capitalized module name. I.e. `file.res` will be compiled into the module `File`. To simplify and minimize the disconnect here, the convention is therefore to capitalize file names.
## Signatures
A module's type is called a "signature", and can be written explicitly. If a
module is like a `.res` (implementation) file, then a module's signature is like
a `.resi` (interface) file.
### Creation
To create a signature, use the `module type` keyword. The signature name must start with a
**capital letter**. Whatever you could place in a `.resi` file, you may place
inside a signature definition's `{}` block.
```res example
/* Picking up previous section's example */
module type EstablishmentType = {
type profession
let getProfession: profession => string
}
```
```js
// Empty output
```
A signature defines the list of requirements that a module must satisfy in order
for that module to match the signature. Those requirements are of the form:
- `let x: int` requires a `let` binding named `x`, of type `int`.
- `type t = someType` requires a type field `t` to be equal to `someType`.
- `type t` requires a type field `t`, but without imposing any requirements on the actual, concrete type of `t`. We'd use `t` in other entries in the signature to describe relationships, e.g. `let makePair: t => (t, t)` but we cannot, for example, assume that `t` is an `int`. This gives us great, enforced abstraction abilities.
To illustrate the various kinds of type entries, consider the above signature
`EstablishmentType` which requires that a module:
- Declare a type named `profession`.
- Must include a function that takes in a value of the type `profession` and returns a string.
**Note**:
Modules of the type `EstablishmentType` can contain more fields than the
signature declares, just like the module `School` in the previous section (if we
choose to assign it the type `EstablishmentType`. Otherwise, `School` exposes
every field). This effectively makes the `person1` field an enforced
implementation detail! Outsiders can't access it, since it's not present in the
signature; the signature **constrained** what others can access.
The type `EstablishmentType.profession` is **abstract**: it doesn't have a
concrete type; it's saying "I don't care what the actual type is, but it's used
as input to `getProfession`". This is useful to fit many modules under the same
interface:
```res
module Company: EstablishmentType = {
type profession = CEO | Designer | Engineer | ...
let getProfession = (person) => ...
let person1 = ...
let person2 = ...
}
```
```js
function getProfession(person) {
...
}
var person1 = ...
var person2 = ...
var Company = {
getProfession: getProfession,
person1: person1,
person2: person2
};
```
It's also useful to hide the underlying type as an implementation detail others
can't rely on. If you ask what the type of `Company.profession` is, instead of
exposing the variant, it'll only tell you "it's `Company.profession`".
### Extending module signatures
Like modules themselves, module signatures can also be extended by other module signatures using `include`. Again, **heavily discouraged**:
```res example
module type BaseComponent = {
let defaultGreeting: string
let getAudience: (~excited: bool) => string
}
module type ActualComponent = {
/* the BaseComponent signature is copied over */
include BaseComponent
let render: unit => string
}
```
```js
// Empty output
```
**Note**: `BaseComponent` is a module **type**, not an actual module itself!
If you do not have a defined module type, you can extract it from an actual module
using `include (module type of ActualModuleName)`. For example, we can extend the
`List` module from the standard library, which does not define a module
type.
```res example
module type MyList = {
include (module type of List)
let myListFun: list<'a> => list<'a>
}
```
```js
// Empty output
```
### Every `.resi` file is a signature
Similar to how a `React.res` file implicitly defines a module `React`, a file
`React.resi` implicitly defines a signature for `React`. If `React.resi` isn't
provided, the signature of `React.res` defaults to exposing all the fields of the
module. Because they don't contain implementation files, `.resi` files are used
in the ecosystem to also document the public API of their corresponding modules.
```res example
/* file React.res (implementation. Compiles to module React) */
type state = int
let render = (str) => str
```
```js
function render(str) {
return str;
}
```
```res sig
/* file React.resi (interface. Compiles to the signature of React.res) */
type state = int
let render: string => string
```
## Module Functions
Modules can be passed to functions! It would be the equivalent of passing a file
as a first-class item. However, modules are at a different "layer" of the
language than other common concepts, so we can't pass them to *regular*
functions. Instead, we pass them to special functions called module functions.
The syntax for defining and using module functions is very much like the syntax
for defining and using regular functions. The primary differences are:
- Module functions use the `module` keyword instead of `let`.
- Module functions take modules as arguments and return a module.
- Module functions *require* annotating arguments.
- Module functions must start with a capital letter (just like modules/signatures).
Here's an example `MakeSet` module function, that takes in a module of the type
`Comparable` and returns a new set that can contain such comparable items.
```res prelude
module type Comparable = {
type t
let equal: (t, t) => bool
}
module MakeSet = (Item: Comparable) => {
// let's use a list as our naive backing data structure
type backingType = list
let empty = list{}
let add = (currentSet: backingType, newItem: Item.t): backingType =>
// if item exists
if currentSet->List.some(x => Item.equal(x, newItem)) {
currentSet // return the same (immutable) set (a list really)
} else {
list{
newItem,
...currentSet // prepend to the set and return it
}
}
}
```
```js
var List = require("./stdlib/list.js");
function MakeSet(Item) {
var add = function(currentSet, newItem) {
if (
List.exists(function(x) {
return Item.equal(x, newItem);
}, currentSet)
) {
return currentSet;
} else {
return {
hd: newItem,
tl: currentSet,
};
}
};
return {
empty: /* [] */ 0,
add: add,
};
}
```
Module functions can be applied using function application syntax. In this case, we're
creating a set, whose items are pairs of integers.
```res example
module IntPair = {
type t = (int, int)
let equal = ((x1: int, y1: int), (x2, y2)) => x1 == x2 && y1 == y2
let create = (x, y) => (x, y)
}
/* IntPair abides by the Comparable signature required by MakeSet */
module SetOfIntPairs = MakeSet(IntPair)
```
```js
function equal(param, param$1) {
if (param[0] === param$1[0]) {
return param[1] === param$1[1];
} else {
return false;
}
}
function create(x, y) {
return [x, y];
}
var IntPair = {
equal: equal,
create: create,
};
var SetOfIntPairs = {
empty: /* [] */ 0,
add: add,
};
```
### Module functions types
Like with module types, module function types also act to constrain and hide what we may
assume about module functions. The syntax for module function types are consistent with those
for function types, but with types capitalized to represent the signatures of
modules the module functions accepts as arguments and return values. In the
previous example, we're exposing the backing type of a set; by giving `MakeSet`
a module function signature, we can hide the underlying data structure!
```res
module type Comparable = ...
module type MakeSetType = (Item: Comparable) => {
type backingType
let empty: backingType
let add: (backingType, Item.t) => backingType
}
module MakeSet: MakeSetType = (Item: Comparable) => {
...
}
```
```js
// Empty output
```
## Exotic Module Filenames
**Since 8.3**
It is possible to use non-conventional characters in your filenames (which is sometimes needed for specific JS frameworks). Here are some examples:
- `src/Button.ios.res`
- `pages/[id].res`
Please note that modules with an exotic filename will not be accessible from other ReScript modules.
## Tips & Tricks
Modules and module functions are at a different "layer" of language than the rest (functions, let bindings, data structures, etc.). For example, you can't easily pass them into a tuple or record. Use them judiciously, if ever! Lots of times, just a record or a function is enough.
---
title: "Mutation"
description: "Imperative and mutative programming capabilities in ReScript"
canonical: "/docs/manual/v11.0.0/mutation"
---
# Mutation
ReScript has great traditional imperative & mutative programming capabilities. You should use these features sparingly, but sometimes they allow your code to be more performant and written in a more familiar pattern.
## Mutate Let-binding
Let-bindings are immutable, but you can wrap it with a `ref`, exposed as a record with a single mutable field in the standard library:
```res prelude
let myValue = ref(5)
```
```js
var myValue = {
contents: 5
};
```
## Usage
You can get the actual value of a `ref` box through accessing its `contents` field:
```res example
let five = myValue.contents // 5
```
```js
var five = myValue.contents;
```
Assign a new value to `myValue` like so:
```res example
myValue.contents = 6
```
```js
myValue.contents = 6;
```
We provide a syntax sugar for this:
```res example
myValue := 6
```
```js
myValue.contents = 6;
```
Note that the previous binding `five` stays `5`, since it got the underlying item on the `ref` box, not the `ref` itself.
**Note**: you might see in the JS output tabs above that `ref` allocates an object. Worry not; local, non-exported `ref`s allocations are optimized away.
## Tip & Tricks
Before reaching for `ref`, know that you can achieve lightweight, local "mutations" through [overriding let bindings](let-binding.md#binding-shadowing).
---
title: "Newcomer Examples"
description: "Quick examples for users new to ReScript"
canonical: "/docs/manual/v11.0.0/newcomer-examples"
---
# Newcomer Examples
An example is worth a thousand words.
This section is dedicated to newcomers trying to figure out general idioms & conventions. If you're a beginner who's got a good idea for an example, please suggest an edit!
## Use the [`option` type](null-undefined-option.md)
```res example
let possiblyNullValue1 = None
let possiblyNullValue2 = Some("Hello")
switch possiblyNullValue2 {
| None => Console.log("Nothing to see here.")
| Some(message) => Console.log(message)
}
```
```js
var possiblyNullValue1;
var possiblyNullValue2 = "Hello";
if (possiblyNullValue2 !== undefined) {
console.log(possiblyNullValue2);
} else {
console.log("Nothing to see here.");
}
```
## Create a Parametrized Type
```res example
type universityStudent = {gpa: float}
type response<'studentType> = {
status: int,
student: 'studentType,
}
```
```js
// Empty output
```
## Creating a JS Object
```res example
let student1 = {
"name": "John",
"age": 30,
}
```
```js
var student1 = {
name: "John",
age: 30,
};
```
Or using [record](record.md):
```res example
type payload = {
name: string,
age: int,
}
let student1 = {
name: "John",
age: 30,
}
```
```js
var student1 = {
name: "John",
age: 30,
};
```
## Modeling a JS Module with Default Export
See [here](import-from-export-to-js.md#import-a-javascript-module-itself-es6-module-format).
## Checking for JS nullable types using the `option` type
For a function whose argument is passed a JavaScript value that's potentially `null` or `undefined`, it's idiomatic to convert it to an `option`. The conversion is done through the helper functions in ReScript's [`Nullable`](api/core/nullable#value-toOption) module. In this case, `toOption`:
```res example
let greetByName = (possiblyNullName) => {
let optionName = Nullable.toOption(possiblyNullName)
switch optionName {
| None => "Hi"
| Some(name) => "Hello " ++ name
}
}
```
```js
function greetByName(possiblyNullName) {
if (possiblyNullName == null) {
return "Hi";
} else {
return "Hello " + possiblyNullName;
}
}
```
This check compiles to `possiblyNullName == null` in JS, so checks for the presence of `null` or `undefined`.
---
title: "Null, Undefined and Option"
description: "JS interop with nullable and optional values in ReScript"
canonical: "/docs/manual/v11.0.0/null-undefined-option"
---
# Null, Undefined and Option
ReScript itself doesn't have the notion of `null` or `undefined`. This is a _great_ thing, as it wipes out an entire category of bugs. No more `undefined is not a function`, and `cannot access someAttribute of undefined`!
However, the **concept** of a potentially nonexistent value is still useful, and safely exists in our language.
We represent the existence and nonexistence of a value by wrapping it with the `option` type. Here's its definition from the standard library:
```res example
type option<'a> = None | Some('a)
```
```js
// Empty output
```
It means "a value of type option is either None (representing nothing) or that actual value wrapped in a Some".
**Note** how the `option` type is just a regular [variant](variant.md).
## Example
Here's a normal value:
```res example
let licenseNumber = 5
```
```js
var licenseNumber = 5;
```
To represent the concept of "maybe null", you'd turn this into an `option` type by wrapping it. For the sake of a more illustrative example, we'll put a condition around it:
```res
let licenseNumber =
if personHasACar {
Some(5)
} else {
None
}
```
```js
var licenseNumber = personHasACar ? 5 : undefined;
```
Later on, when another piece of code receives such value, it'd be forced to handle both cases through [pattern matching](pattern-matching-destructuring.md):
```res
switch licenseNumber {
| None =>
Console.log("The person doesn't have a car")
| Some(number) =>
Console.log("The person's license number is " ++ Int.toString(number))
}
```
```js
var number = licenseNumber;
if (number !== undefined) {
console.log("The person's license number is " + number.toString());
} else {
console.log("The person doesn't have a car");
}
```
By turning your ordinary number into an `option` type, and by forcing you to handle the `None` case, the language effectively removed the possibility for you to mishandle, or forget to handle, a conceptual `null` value! **A pure ReScript program doesn't have null errors**.
## Interoperate with JavaScript `undefined` and `null`
The `option` type is common enough that we special-case it when compiling to JavaScript:
```res example
let x = Some(5)
```
```js
var x = 5;
```
simply compiles down to `5`, and
```res example
let x = None
```
```js
var x;
```
compiles to `undefined`! If you've got e.g. a string in JavaScript that you know might be `undefined`, type it as `option` and you're done! Likewise, you can send a `Some(5)` or `None` to the JS side and expect it to be interpreted correctly =)
### Caveat 1
The option-to-undefined translation isn't perfect, because on our side, `option` values can be composed:
```res example
let x = Some(Some(Some(5)))
```
```js
var x = 5;
```
This still compiles to `5`, but this gets troublesome:
```res example
let x = Some(None)
```
```js
var Caml_option = require("./stdlib/caml_option.js");
var x = Caml_option.some(undefined);
```
(See output tab).
What's this `Caml_option.some` thing? Why can't this compile to `undefined`? Long story short, when dealing with a polymorphic `option` type (aka `option<'a>`, for any `'a`), many operations become tricky if we don't mark the value with some special annotation. If this doesn't make sense, don't worry; just remember the following rule:
- **Never, EVER, pass a nested `option` value (e.g. `Some(Some(Some(5)))`) into the JS side.**
- **Never, EVER, annotate a value coming from JS as `option<'a>`. Always give the concrete, non-polymorphic type.**
### Caveat 2
Unfortunately, lots of times, your JavaScript value might be _both_ `null` or `undefined`. In that case, you unfortunately can't type such value as e.g. `option`, since our `option` type only checks for `undefined` and not `null` when dealing with a `None`.
#### Solution: More Sophisticated `undefined` & `null` Interop
To solve this, we provide access to more elaborate `null` and `undefined` helpers through the [`Nullable`](api/core/nullable) module. This somewhat works like an `option` type, but is different from it.
#### Examples
To create a JS `null`, use the value `Nullable.null`. To create a JS `undefined`, use `Nullable.undefined` (you can naturally use `None` too, but that's not the point here; the `Nullable.*` helpers wouldn't work with it).
If you're receiving, for example, a JS string that can be `null` and `undefined`, type it as:
```res example
@module("MyConstant") external myId: Nullable.t = "myId"
```
```js
// Empty output
```
To create such a nullable string from our side (presumably to pass it to the JS side, for interop purpose), do:
```res example
@module("MyIdValidator") external validate: Nullable.t => bool = "validate"
let personId: Nullable.t = Nullable.make("abc123")
let result = validate(personId)
```
```js
var MyIdValidator = require("MyIdValidator");
var personId = "abc123";
var result = MyIdValidator.validate(personId);
```
The `return` part "wraps" a string into a nullable string, to make the type system understand and track the fact that, as you pass this value around, it's not just a string, but a string that can be `null` or `undefined`.
#### Convert to/from `option`
`Nullable.fromOption` converts from a `option` to `Nullable.t`. `Nullable.toOption` does the opposite.
---
title: "Object"
description: "Interoping with JS objects in ReScript"
canonical: "/docs/manual/v11.0.0/object"
---
# Object
ReScript objects are like [records](record.md), but:
- No type declaration needed.
- Structural and more polymorphic, [unlike records](record.md#record-types-are-found-by-field-name).
- Doesn't support updates unless the object comes from the JS side.
- Doesn't support [pattern matching](pattern-matching-destructuring).
Although ReScript records compile to clean JavaScript objects, ReScript objects are a better candidate for emulating/binding to JS objects, as you'll see.
## Type Declaration
**Optional**, unlike for records. The type of an object is inferred from the value, so you never really need to write down its type definition. Nevertheless, here's its type declaration syntax:
```res prelude
type person = {
"age": int,
"name": string
};
```
```js
// Empty output
```
Visually similar to record type's syntax, with the field names quoted.
## Creation
To create a new object:
```res example
let me = {
"age": 5,
"name": "Big ReScript"
}
```
```js
var me = {
"age": 5,
"name": "Big ReScript"
};
```
**Note**: as said above, unlike for record, this `me` value does **not** try to find a conforming type declaration with the field `"age"` and `"name"`; rather, the type of `me` is inferred as `{"age": int, "name": string}`. This is convenient, but also means this code passes type checking without errors:
```res
type person = {
"age": int
};
let me = {
"age": "hello!" // age is a string. No error.
}
```
```js
var me = {
"age": "hello!"
};
```
Since the type checker doesn't try to match `me` with the type `person`. If you ever want to force an object value to be of a predeclared object type, just annotate the value:
```res
let me: person = {
"age": "hello!"
}
```
Now the type system will error properly.
## Access
```res
let age = me["age"]
```
```js
var age = me["age"];
```
## Update
Disallowed unless the object is a binding that comes from the JavaScript side. In that case, use `=`
```res example
type student = {
@set "age": int,
@set "name": string,
}
@module("MyJSFile") external student1: student = "student1"
student1["name"] = "Mary"
```
```js
var MyJSFile = require("MyJSFile");
MyJSFile.student1.name = "Mary";
```
## Combine Types
You can spread one object type definition into another using `...`:
```res example
type point2d = {
"x": float,
"y": float,
}
type point3d = {
...point2d,
"z": float,
}
let myPoint: point3d = {
"x": 1.0,
"y": 2.0,
"z": 3.0,
}
```
```js
var myPoint = {
x: 1.0,
y: 2.0,
z: 3.0
};
```
This only works with object types, not object values!
## Tips & Tricks
Since objects don't require type declarations, and since ReScript infers all the types for you, you get to very quickly and easily (and dangerously) bind to any JavaScript API. Check the JS output tab:
```res example
// The type of document is just some random type 'a
// that we won't bother to specify
@val external document: 'a = "document"
// call a method
document["addEventListener"]("mouseup", _event => {
Console.log("clicked!")
})
// get a property
let loc = document["location"]
// set a property
document["location"]["href"] = "rescript-lang.org"
```
```js
document.addEventListener("mouseup", function(_event) {
console.log("clicked!");
});
var loc = document.location;
document.location.href = "rescript-lang.org";
```
The `external` feature and the usage of this trick are also documented in the [external](external#tips--tricks) section later. It's an excellent way to start writing some ReScript code without worrying about whether bindings to a particular library exists.
---
title: "Overview"
metaTitle: "Language Features Overview"
description: "A quick overview on ReScript's syntax"
canonical: "/docs/manual/v11.0.0/overview"
---
# Overview
## Comparison to JS
### Semicolon
| JavaScript | ReScript |
| ---------------------------------- | -------------------- |
| Rules enforced by linter/formatter | No semicolon needed! |
### Comments
| JavaScript | ReScript |
| -------------------- | -------------------------------- |
| `// Line comment` | Same |
| `/* Comment */` | Same |
| `/** Doc Comment */` | `/** Before Types/Values */` |
| | `/*** Standalone Doc Comment */` |
### Variable
| JavaScript | ReScript |
| ----------------------- | ------------------------------------- |
| `const x = 5;` | `let x = 5` |
| `var x = y;` | No equivalent (thankfully) |
| `let x = 5; x = x + 1;` | `let x = ref(5); x := x.contents + 1` |
### String & Character
| JavaScript | ReScript |
| ---------------------------- | --------------------- |
| `"Hello world!"` | Same |
| `'Hello world!'` | Strings must use `"` |
| `"hello " + "world"` | `"hello " ++ "world"` |
| `` `hello ${message}` `` | Same |
| `` sql`select ${fnName};` `` | Same |
### Boolean
| JavaScript | ReScript |
| ----------------------------------------------------- | ---------------------------------------------- |
| `true`, `false` | Same |
| `!true` | Same |
| ||, `&&`, `<=`, `>=`, `<`, `>` | Same |
| `a === b`, `a !== b` | Same |
| No deep equality (recursive compare) | `a == b`, `a != b` |
| `a == b` | No equality with implicit casting (thankfully) |
### Number
| JavaScript | ReScript |
| ----------- | ------------ |
| `3` | Same \* |
| `3.1415` | Same |
| `3 + 4` | Same |
| `3.0 + 4.5` | `3.0 +. 4.5` |
| `5 % 3` | `mod(5, 3)` |
\* JS has no distinction between integer and float.
### Object/Record
| JavaScript | ReScript |
| ------------------- | --------------------------------------- |
| no types | `type point = {x: int, mutable y: int}` |
| `{x: 30, y: 20}` | Same |
| `point.x` | Same |
| `point.y = 30;` | Same |
| `{...point, x: 30}` | Same |
### Array
| JavaScript | ReScript |
| ------------------ | --------------------- |
| `[1, 2, 3]` | Same |
| `myArray[1] = 10` | Same |
| `[1, "Bob", true]` | `(1, "Bob", true)` \* |
\* ReScript does not have heterogenous arrays. Use tuples or [Untagged Variants](variant#untagged-variants) instead.
### Null
| JavaScript | ReScript |
| ------------------- | --------- |
| `null`, `undefined` | `None` \* |
\* Again, only a spiritual equivalent; we don't have nulls, nor null bugs! But we do have an `option` type for when you actually need nullability.
### Function
| JavaScript | ReScript |
| ------------------------------- | ---------------------------- |
| `arg => retVal` | Same |
| `function named(arg) {...}` | `let named = (arg) => {...}` |
| `const f = function(arg) {...}` | `let f = (arg) => {...}` |
| `add(4, add(5, 6))` | Same |
### Async Function / Await
| JavaScript | ReScript |
| --------------------------------------- | ----------------------------------------------------- |
| `async (arg) => {...}` | Same |
| `async function named(arg) {...}` | `let named = async (arg) => {...}` |
| `await somePromise` | Same |
| `async (arg): Promise => {...}` | `async (arg): string => {...}` (note the return type) |
### Blocks
```
let myFun = (x, y) => {
let doubleX = x + x
let doubleY = y + y
doubleX + doubleY
}
```
### If-else
| JavaScript | ReScript |
| --------------------- | --------------------------------------------------------------------------------- |
| `if (a) {b} else {c}` | `if a {b} else {c}` \* |
| `a ? b : c` | Same |
| `switch` | `switch` but [super-powered pattern matching!](pattern-matching-destructuring.md) |
\* Our conditionals are always expressions! You can write `let result = if a {"hello"} else {"bye"}`
### Destructuring
| JavaScript | ReScript |
| ----------------------------- | --------------------------- |
| `const {a, b} = data` | `let {a, b} = data` |
| `const [a, b] = data` | `let [a, b] = data` \* |
| `const {a: aa, b: bb} = data` | `let {a: aa, b: bb} = data` |
\* Gives good compiler warning that `data` might not be of length 2.
### Loop
| JavaScript | ReScript |
| ------------------------------------- | ---------------------------- |
| `for (let i = 0; i <= 10; i++) {...}` | `for i in 0 to 10 {...}` |
| `for (let i = 10; i >= 0; i--) {...}` | `for i in 10 downto 0 {...}` |
| `while (true) {...}` | `while true {...}` |
### JSX
| JavaScript | ReScript |
| ----------------------------------------- | -------------------------- |
| `` | Same |
| `` | `` \* |
| `` | `` |
| No children spread | `...children` |
\* Argument punning!
### Exception
| JavaScript | ReScript |
| ----------------------------------------- | -------------------------------------------- |
| `throw new SomeError(...)` | `raise(SomeError(...))` |
| `try {a} catch (err) {...} finally {...}` | `try a catch { \| SomeError(err) => ...}` \* |
\* No finally.
### Blocks
The last expression of a block delimited by `{}` implicitly returns (including function body). In JavaScript, this can only be simulated via an immediately-invoked function expression (since function bodies have their own local scope).
JavaScript
ReScript
```
let result = (function() {
const x = 23;
const y = 34;
return x + y;
})();
```
```
let result = {
let x = 23
let y = 34
x + y
}
```
## Common Features' JS Output
| Feature | Example | JavaScript Output |
| ------------------------------- | ------------------------------------ | ------------------------------------------ |
| String | `"Hello"` | `"Hello"` |
| String Interpolation | `` `Hello ${message}` `` | `"Hello " + message` |
| Character (disrecommended) | `'x'` | `120` (char code) |
| Integer | `23`, `-23` | `23`, `-23` |
| Float | `23.0`, `-23.0` | `23.0`, `-23.0` |
| Integer Addition | `23 + 1` | `23 + 1` |
| Float Addition | `23.0 +. 1.0` | `23.0 + 1.0` |
| Integer Division/Multiplication | `2 / 23 * 1` | `2 / 23 * 1` |
| Float Division/Multiplication | `2.0 /. 23.0 *. 1.0` | `2.0 / 23.0 * 1.0` |
| Float Exponentiation | `2.0 ** 3.0` | `Math.pow(2.0, 3.0)` |
| String Concatenation | `"Hello " ++ "World"` | `"Hello " + "World"` |
| Comparison | `>`, `<`, `>=`, `<=` | `>`, `<`, `>=`, `<=` |
| Boolean operation | `!`, `&&`, || | `!`, `&&`, || |
| Shallow and deep Equality | `===`, `==` | `===`, `==` |
| List (disrecommended) | `list{1, 2, 3}` | `{hd: 1, tl: {hd: 2, tl: {hd: 3, tl: 0}}}` |
| List Prepend | `list{a1, a2, ...oldList}` | `{hd: a1, tl: {hd: a2, tl: theRest}}` |
| Array | `[1, 2, 3]` | `[1, 2, 3]` |
| Record | `type t = {b: int}; let a = {b: 10}` | `var a = {b: 10}` |
| Multiline Comment | `/* Comment here */` | Not in output |
| Single line Comment | `// Comment here` | Not in output |
_Note that this is a cleaned-up comparison table; a few examples' JavaScript output are slightly different in reality._
---
title: "Pattern Matching / Destructuring"
description: "Pattern matching and destructuring complex data structures in ReScript"
canonical: "/docs/manual/v11.0.0/pattern-matching-destructuring"
---
# Pattern Matching / Destructuring
One of ReScript's **best** feature is our pattern matching. Pattern matching combines 3 brilliant features into one:
- Destructuring.
- `switch` based on shape of data.
- Exhaustiveness check.
We'll dive into each aspect below.
## Destructuring
Even JavaScript has destructuring, which is "opening up" a data structure to extract the parts we want and assign variable names to them:
```res example
let coordinates = (10, 20, 30)
let (x, _, _) = coordinates
Console.log(x) // 10
```
```js
var coordinates = [10, 20, 30];
var x = 10;
console.log(10);
```
Destructuring works with most built-in data structures:
```res
// Record
type student = {name: string, age: int}
let student1 = {name: "John", age: 10}
let {name} = student1 // "John" assigned to `name`
// Variant
type result =
| Success(string)
let myResult = Success("You did it!")
let Success(message) = myResult // "You did it!" assigned to `message`
```
```js
var student1 = {
name: "John",
age: 10
};
var name = "John";
var myResult = /* Success */{
_0: "You did it!"
};
var message = "You did it!"
var myArray = [1, 2, 3];
if (myArray.length !== 2) {
throw {
RE_EXN_ID: "Match_failure",
_1: [
"playground.res",
14,
4
],
Error: new Error()
};
}
var item1 = myArray[0];
var item2 = myArray[1];
var myList = {
hd: 1,
tl: {
hd: 2,
tl: {
hd: 3,
tl: /* [] */0
}
}
};
// ...
```
You can also use destructuring anywhere you'd usually put a binding:
```res example
type result =
| Success(string)
let displayMessage = (Success(m)) => {
// we've directly extracted the success message
// string by destructuring the parameter
Console.log(m)
}
displayMessage(Success("You did it!"))
```
```js
function displayMessage(m) {
console.log(m._0);
}
displayMessage(/* Success */{
_0: "You did it!"
});
```
For a record, you can rename the field while destructuring:
```res
let {name: n} = student1 // "John" assigned to `n`
```
```js
var n = "John";
```
You _can_ in theory destructure array and list at the top level too:
```res
let myArray = [1, 2, 3]
let [item1, item2, _] = myArray
// 1 assigned to `item1`, 2 assigned to `item2`, 3rd item ignored
let myList = list{1, 2, 3}
let list{head, ...tail} = myList
// 1 assigned to `head`, `list{2, 3}` assigned to tail
```
But the array example is **highly disrecommended** (use tuple instead) and the list example will error on you. They're only there for completeness' sake. As you'll see below, the proper way of using destructuring array and list is using `switch`.
## `switch` Based on Shape of Data
While the destructuring aspect of pattern matching is nice, it doesn't really change the way you think about structuring your code. One paradigm-changing way of thinking about your code is to execute some code based on the shape of the data.
Consider a variant:
```res prelude
type payload =
| BadResult(int)
| GoodResult(string)
| NoResult
```
```js
// Empty output
```
We'd like to handle each of the 3 cases differently. For example, print a success message if the value is `GoodResult(...)`, do something else when the value is `NoResult`, etc.
In other languages, you'd end up with a series of if-elses that are hard to read and error-prone. In ReScript, you can instead use the supercharged `switch` pattern matching facility to destructure the value while calling the right code based on what you destructured:
```res example
let data = GoodResult("Product shipped!")
switch data {
| GoodResult(theMessage) =>
Console.log("Success! " ++ theMessage)
| BadResult(errorCode) =>
Console.log("Something's wrong. The error code is: " ++ Int.toString(errorCode))
| NoResult =>
Console.log("Bah.")
}
```
```js
var data = {
TAG: "GoodResult",
_0: "Product shipped!"
};
if (typeof data !== "object") {
console.log("Bah.");
} else if (data.TAG === "BadResult") {
console.log("Something's wrong. The error code is: " + "Product shipped!".toString());
} else {
console.log("Success! Product shipped!");
}
```
In this case, `message` will have the value `"Success! Product shipped!"`.
Suddenly, your if-elses that messily checks some structure of the value got turned into a clean, compiler-verified, linear list of code to execute based on exactly the shape of the value.
### Complex Examples
Here's a real-world scenario that'd be a headache to code in other languages. Given this data structure:
```res prelude
type status = Vacations(int) | Sabbatical(int) | Sick | Present
type reportCard = {passing: bool, gpa: float}
type student = {name: string, status: status, reportCard: reportCard}
type person =
| Teacher({name: string, age: int})
| Student(student)
```
```js
// Empty output
```
Imagine this requirement:
- Informally greet a person who's a teacher and if his name is Mary or Joe.
- Greet other teachers formally.
- If the person's a student, congratulate him/her score if they passed the semester.
- If the student has a gpa of 0 and is on vacations or sabbatical, display a different message.
- A catch-all message for a student.
ReScript can do this easily!
```res prelude
let person1 = Teacher({name: "Jane", age: 35})
let message = switch person1 {
| Teacher({name: "Mary" | "Joe"}) =>
`Hey, still going to the party on Saturday?`
| Teacher({name}) =>
// this is matched only if `name` isn't "Mary" or "Joe"
`Hello ${name}.`
| Student({name, reportCard: {passing: true, gpa}}) =>
`Congrats ${name}, nice GPA of ${Float.toString(gpa)} you got there!`
| Student({
reportCard: {gpa: 0.0},
status: Vacations(daysLeft) | Sabbatical(daysLeft)
}) =>
`Come back in ${Int.toString(daysLeft)} days!`
| Student({status: Sick}) =>
`How are you feeling?`
| Student({name}) =>
`Good luck next semester ${name}!`
}
```
```js
var person1 = {
TAG: "Teacher",
name: "Jane",
age: 35
};
var message;
if (person1.TAG === "Teacher") {
message = "Hello Jane.";
} else {
var match = "Jane";
var match$1 = match.status;
var name = match.name;
var match$2 = match.reportCard;
if (match$2.passing) {
message = "Congrats " + name + ", nice GPA of " + match$2.gpa.toString() + " you got there!";
} else {
var exit = 0;
if (typeof match$1 !== "object") {
message = match$1 === "Sick" ? "How are you feeling?" : "Good luck next semester " + name + "!";
} else {
exit = 1;
}
if (exit === 1) {
message = match.reportCard.gpa !== 0.0 ? "Good luck next semester " + name + "!" : "Come back in " + match$1._0.toString() + " days!";
}
}
}
```
**Note** how we've:
- drilled deep down into the value concisely
- using a **nested pattern check** `"Mary" | "Joe"` and `Vacations | Sabbatical`
- while extracting the `daysLeft` number from the latter case
- and assigned the greeting to the binding `message`.
Here's another example of pattern matching, this time on an inline tuple.
```res
type animal = Dog | Cat | Bird
let categoryId = switch (isBig, myAnimal) {
| (true, Dog) => 1
| (true, Cat) => 2
| (true, Bird) => 3
| (false, Dog | Cat) => 4
| (false, Bird) => 5
}
```
```js
var categoryId = isBig ? (myAnimal + 1) | 0 : myAnimal >= 2 ? 5 : 4;
```
**Note** how pattern matching on a tuple is equivalent to a 2D table:
isBig \ myAnimal | Dog | Cat | Bird
-----------------|-----|-----|------
true | 1 | 2 | 3
false | 4 | 4 | 5
### Fall-Through Patterns
The nested pattern check, demonstrated in the earlier `person` example, also works at the top level of a `switch`:
```res prelude
let myStatus = Vacations(10)
switch myStatus {
| Vacations(days)
| Sabbatical(days) => Console.log(`Come back in ${Int.toString(days)} days!`)
| Sick
| Present => Console.log("Hey! How are you?")
}
```
```js
var myStatus = {
TAG: /* Vacations */0,
_0: 10
};
if (typeof myStatus === "number") {
console.log("Hey! How are you?");
} else {
console.log("Come back in " + (10).toString() + " days!");
}
```
Having multiple cases fall into the same handling can clean up certain types of logic.
### Ignore Part of a Value
If you have a value like `Teacher(payload)` where you just want to pattern match on the `Teacher` part and ignore the `payload` completely, you can use the `_` wildcard like this:
```res example
switch person1 {
| Teacher(_) => Console.log("Hi teacher")
| Student(_) => Console.log("Hey student")
}
```
```js
if (person1.TAG === "Teacher") {
console.log("Hi teacher");
} else {
console.log("Hey student");
}
```
`_` also works at the top level of the `switch`, serving as a catch-all condition:
```res example
switch myStatus {
| Vacations(_) => Console.log("Have fun!")
| _ => Console.log("Ok.")
}
```
```js
if (typeof myStatus !== "object" || myStatus.TAG !== "Vacations") {
console.log("Ok.");
} else {
console.log("Have fun!");
}
```
**Do not** abuse a top-level catch-all condition. Instead, prefer writing out all the cases:
```res example
switch myStatus {
| Vacations(_) => Console.log("Have fun!")
| Sabbatical(_) | Sick | Present => Console.log("Ok.")
}
```
```js
if (typeof myStatus !== "object" || myStatus.TAG !== "Vacations") {
console.log("Ok.");
} else {
console.log("Have fun!");
}
```
Slightly more verbose, but a one-time writing effort. This helps when you add a new variant case e.g. `Quarantined` to the `status` type and need to update the places that pattern match on it. A top-level wildcard here would have accidentally and silently continued working, potentially causing bugs.
### If Clause
Sometime, you want to check more than the shape of a value. You want to also run some arbitrary check on it. You might be tempted to write this:
```res example
switch person1 {
| Teacher(_) => () // do nothing
| Student({reportCard: {gpa}}) =>
if gpa < 0.5 {
Console.log("What's happening")
} else {
Console.log("Heyo")
}
}
```
```js
if (person1.TAG !== "Teacher") {
if ("Jane".reportCard.gpa < 0.5) {
console.log("What's happening");
} else {
console.log("Heyo");
}
}
```
`switch` patterns support a shortcut for the arbitrary `if` check, to keep your pattern linear-looking:
```res example
switch person1 {
| Teacher(_) => () // do nothing
| Student({reportCard: {gpa}}) if gpa < 0.5 =>
Console.log("What's happening")
| Student(_) =>
// fall-through, catch-all case
Console.log("Heyo")
}
```
```js
if (person1.TAG) {
if (person1.reportCard.gpa < 0.5) {
console.log("What's happening");
} else {
console.log("Heyo");
}
}
```
**Note:** Rescript versions < 9.0 had a `when` clause, not an `if` clause. Rescript 9.0 changed `when` to `if`. (`when` may still work, but is deprecated.)
### Match on Exceptions
If the function throws an exception (covered later), you can also match on _that_, in addition to the function's normally returned values.
```res
switch List.find(i => i === theItem, myItems) {
| item => Console.log(item)
| exception Not_found => Console.log("No such item found!")
}
```
```js
var exit = 0;
var item;
try {
item = List.find(function(i) {
return i === theItem;
}, myItems);
exit = 1;
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
if (exn.RE_EXN_ID === "Not_found") {
console.log("No such item found!");
} else {
throw exn;
}
}
if (exit === 1) {
console.log(item);
}
```
### Match on Array
```res example
let students = ["Jane", "Harvey", "Patrick"]
switch students {
| [] => Console.log("There are no students")
| [student1] =>
Console.log("There's a single student here: " ++ student1)
| manyStudents =>
// display the array of names
Console.log2("The students are: ", manyStudents)
}
```
```js
var students = ["Jane", "Harvey", "Patrick"];
var len = students.length;
if (len !== 1) {
if (len !== 0) {
console.log("The students are: ", students);
} else {
console.log("There are no students");
}
} else {
var student1 = students[0];
console.log("There's a single student here: " + student1);
}
```
### Match on List
Pattern matching on list is similar to array, but with the extra feature of extracting the tail of a list (all elements except the first one):
```res example
let rec printStudents = (students) => {
switch students {
| list{} => () // done
| list{student} => Console.log("Last student: " ++ student)
| list{student1, ...otherStudents} =>
Console.log(student1)
printStudents(otherStudents)
}
}
printStudents(list{"Jane", "Harvey", "Patrick"})
```
```js
function printStudents(_students) {
while(true) {
var students = _students;
if (!students) {
return;
}
var otherStudents = students.tl;
var student = students.hd;
if (otherStudents) {
console.log(student);
_students = otherStudents;
continue;
}
console.log("Last student: " + student);
return;
};
}
printStudents({
hd: "Jane",
tl: {
hd: "Harvey",
tl: {
hd: "Patrick",
tl: /* [] */0
}
}
});
```
### Small Pitfall
**Note**: you can only pass literals (i.e. concrete values) as a pattern, not let-binding names or other things. The following doesn't work as expected:
```res example
let coordinates = (10, 20, 30)
let centerY = 20
switch coordinates {
| (x, _centerY, _) => Console.log(x)
}
```
```js
var coordinates = [10, 20, 30];
var centerY = 20;
console.log(10);
```
A first time ReScript user might accidentally write that code, assuming that it's matching on `coordinates` when the second value is of the same value as `centerY`. In reality, this is interpreted as matching on coordinates and assigning the second value of the tuple to the name `centerY`, which isn't what's intended.
## Exhaustiveness Check
As if the above features aren't enough, ReScript also provides arguably the most important pattern matching feature: **compile-time check of missing patterns**.
Let's revisit one of the above examples:
```res
let message = switch person1 {
| Teacher({name: "Mary" | "Joe"}) =>
`Hey, still going to the party on Saturday?`
| Student({name, reportCard: {passing: true, gpa}}) =>
`Congrats ${name}, nice GPA of ${Float.toString(gpa)} you got there!`
| Student({
reportCard: {gpa: 0.0},
status: Vacations(daysLeft) | Sabbatical(daysLeft)
}) =>
`Come back in ${Int.toString(daysLeft)} days!`
| Student({status: Sick}) =>
`How are you feeling?`
| Student({name}) =>
`Good luck next semester ${name}!`
}
```
```js
if (person1.TAG) {
var match$1 = person1.status;
var name = person1.name;
var match$2 = person1.reportCard;
if (match$2.passing) {
"Congrats " + name + ", nice GPA of " + match$2.gpa.toString() + " you got there!";
} else if (typeof match$1 === "number") {
if (match$1 !== 0) {
"Good luck next semester " + name + "!";
} else {
"How are you feeling?";
}
} else if (person1.reportCard.gpa !== 0.0) {
"Good luck next semester " + name + "!";
} else {
"Come back in " + match$1._0.toString() + " days!";
}
} else {
switch (person1.name) {
case "Joe":
case "Mary":
break;
default:
throw {
RE_EXN_ID: "Match_failure",
_1: [
"playground.res",
13,
0
],
Error: new Error()
};
}
}
```
Did you see what we removed? This time, we've omitted the handling of the case where `person1` is `Teacher({name})` when `name` isn't Mary or Joe.
Failing to handle every scenario of a value likely constitutes the majority of program bugs out there. This happens very often when you refactor a piece of code someone else wrote. Fortunately for ReScript, the compiler will tell you so:
```
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
Some({name: ""})
```
**BAM**! You've just erased an entire category of important bugs before you even ran the code. In fact, this is how most of nullable values is handled:
```res example
let myNullableValue = Some(5)
switch myNullableValue {
| Some(_v) => Console.log("value is present")
| None => Console.log("value is absent")
}
```
```js
var myNullableValue = 5;
if (myNullableValue !== undefined) {
console.log("value is present");
} else {
console.log("value is absent");
}
```
If you don't handle the `None` case, the compiler warns. No more `undefined` bugs in your code!
## Conclusion & Tips & Tricks
Hopefully you can see how pattern matching is a game changer for writing correct code, through the concise destructuring syntax, the proper conditions handling of `switch`, and the static exhaustiveness check.
Below is some advice:
Avoid using the wildcard `_` unnecessarily. Using the wildcard `_` will bypass the compiler's exhaustiveness check. Consequently, the compiler will not be able to notify you of probable errors when you add a new case to a variant. Try only using `_` against infinite possibilities, e.g. string, int, etc.
Use the `if` clause sparingly.
**Flatten your pattern-match whenever you can**. This is a real bug remover. Here's a series of examples, from worst to best:
```res example
let optionBoolToBool = opt => {
if opt == None {
false
} else if opt === Some(true) {
true
} else {
false
}
}
```
```js
function optionBoolToBool(opt) {
if (opt === undefined) {
return false;
} else {
return opt === true;
}
}
```
Now that's just silly =). Let's turn it into pattern-matching:
```res example
let optionBoolToBool = opt => {
switch opt {
| None => false
| Some(a) => a ? true : false
}
}
```
```js
function optionBoolToBool(opt) {
if (opt !== undefined && opt) {
return true;
} else {
return false;
}
}
```
Slightly better, but still nested. Pattern-matching allows you to do this:
```res example
let optionBoolToBool = opt => {
switch opt {
| None => false
| Some(true) => true
| Some(false) => false
}
}
```
```js
function optionBoolToBool(opt) {
if (opt !== undefined && opt) {
return true;
} else {
return false;
}
}
```
Much more linear-looking! Now, you might be tempted to do this:
```res example
let optionBoolToBool = opt => {
switch opt {
| Some(true) => true
| _ => false
}
}
```
```js
function optionBoolToBool(opt) {
if (opt !== undefined && opt) {
return true;
} else {
return false;
}
}
```
Which is much more concise, but kills the exhaustiveness check mentioned above; refrain from using that. This is the best:
```res example
let optionBoolToBool = opt => {
switch opt {
| Some(trueOrFalse) => trueOrFalse
| None => false
}
}
```
```js
function optionBoolToBool(opt) {
if (opt !== undefined) {
return opt;
} else {
return false;
}
}
```
Pretty darn hard to make a mistake in this code at this point! Whenever you'd like to use an if-else with many branches, prefer pattern matching instead. It's more concise and [performant](variant#design-decisions) too.
---
title: "Pipe"
description: "The Pipe operator (->)"
canonical: "/docs/manual/v11.0.0/pipe"
---
# Pipe
ReScript provides a tiny but surprisingly useful operator `->`, called the "pipe", that allows you to "flip" your code inside-out. `a(b)` becomes `b->a`. It's a simple piece of syntax that doesn't have any runtime cost.
Why would you use it? Imagine you have the following:
```res
validateAge(getAge(parseData(person)))
```
```js
validateAge(getAge(parseData(person)));
```
This is slightly hard to read, since you need to read the code from the innermost part, to the outer parts. Use pipe to streamline it:
```res
person
->parseData
->getAge
->validateAge
```
```js
validateAge(getAge(parseData(person)));
```
Basically, `parseData(person)` is transformed into `person->parseData`, and `getAge(person->parseData)` is transformed into `person->parseData->getAge`, etc.
**This works when the function takes more than one argument too**.
```res
a(one, two, three)
```
```js
a(one, two, three);
```
is the same as
```res
one->a(two, three)
```
```js
a(one, two, three);
```
This also works with labeled arguments.
Pipes are used to emulate object-oriented programming. For example, `myStudent.getName` in other languages like Java would be `myStudent->getName` in ReScript (equivalent to `getName(myStudent)`). This allows us to have the readability of OOP without the downside of dragging in a huge class system just to call a function on a piece of data.
## Tips & Tricks
Do **not** abuse pipes; they're a means to an end. Inexperienced engineers sometimes shape a library's API to take advantage of the pipe. This is backwards.
## JS Method Chaining
_This section requires understanding of [our binding API](bind-to-js-function.md#object-method)_.
JavaScript's APIs are often attached to objects, and are often chainable, like so:
```js
const result = [1, 2, 3].map(a => a + 1).filter(a => a % 2 === 0);
asyncRequest()
.setWaitDuration(4000)
.send();
```
Assuming we don't need the chaining behavior above, we'd bind to each case of this using [`@send`](/syntax-lookup#send-decorator) from the aforementioned binding API page:
```res prelude
type request
@val external asyncRequest: unit => request = "asyncRequest"
@send external setWaitDuration: (request, int) => request = "setWaitDuration"
@send external send: request => unit = "send"
```
```js
// Empty output
```
You'd use them like this:
```res example
let result = Array.filter(
Array.map([1, 2, 3], a => a + 1),
a => mod(a, 2) == 0
)
send(setWaitDuration(asyncRequest(), 4000))
```
```js
var result = [1, 2, 3].map(function(a) {
return a + 1 | 0;
}).filter(function(a) {
return a % 2 === 0;
});
asyncRequest().setWaitDuration(4000).send();
```
This looks much worse than the JS counterpart! Clean it up visually with pipe:
```res example
let result = [1, 2, 3]
->Array.map(a => a + 1)
->Array.filter(a => mod(a, 2) == 0)
asyncRequest()->setWaitDuration(4000)->send
```
```js
var result = [1, 2, 3].map(function(a) {
return a + 1 | 0;
}).filter(function(a) {
return a % 2 === 0;
});
asyncRequest().setWaitDuration(4000).send();
```
## Pipe Into Variants
You can pipe into a variant's constructor as if it was a function:
```res
let result = name->preprocess->Some
```
```js
var result = preprocess(name);
```
We turn this into:
```res
let result = Some(preprocess(name))
```
```js
var result = preprocess(name);
```
**Note** that using a variant constructor as a function wouldn't work anywhere else beside here.
## Pipe Placeholders
A placeholder is written as an underscore and it tells ReScript that you want to fill in an argument of a function later. These two have equivalent meaning:
```res
let addTo7 = (x) => add3(3, x, 4)
let addTo7 = add3(3, _, 4)
```
Sometimes you don't want to pipe the value you have into the first position. In these cases you can mark a placeholder value to show which argument you would like to pipe into.
Let's say you have a function `namePerson`, which takes a `person` then a `name` argument. If you are transforming a person then pipe will work as-is:
```res
makePerson(~age=47)
->namePerson("Jane")
```
```js
namePerson(makePerson(47), "Jane");
```
If you have a name that you want to apply to a person object, you can use a placeholder:
```res
getName(input)
->namePerson(personDetails, _)
```
```js
var __x = getName(input);
namePerson(personDetails, __x);
```
This allows you to pipe into any positional argument. It also works for named arguments:
```res
getName(input)
->namePerson(~person=personDetails, ~name=_)
```
```js
var __x = getName(input);
namePerson(personDetails, __x);
```
## Triangle Pipe (Deprecated)
You might see usages of another pipe, `|>`, in some codebases. These are deprecated.
Unlike `->` pipe, the `|>` pipe puts the subject as the last (not first) argument of the function. `a |> f(b)` turns into `f(b, a)`.
For a more thorough discussion on the rationale and differences between the two operators, please refer to the [Data-first and Data-last comparison by Javier Chávarri](https://www.javierchavarri.com/data-first-and-data-last-a-comparison/)
---
title: "Polymorphic Variant"
description: "The Polymorphic Variant data structure in ReScript"
canonical: "/docs/manual/v11.0.0/polymorphic-variant"
---
# Polymorphic Variant
Polymorphic variants (or poly variant) are a cousin of [variant](variant). With these differences:
- They start with a `#` and the constructor name doesn't need to be capitalized.
- They don't require an explicit type definition. The type is inferred from usage.
- Values of different poly variant types can share the constructors they have in common (aka, poly variants are "structurally" typed, as opposed to ["nominally" typed](variant#variant-types-are-found-by-field-name)).
They're a convenient and useful alternative to regular variants, but should **not** be abused. See the drawbacks at the end of this page.
## Creation
We provide 3 syntaxes for a poly variant's constructor:
```res
let myColor = #red
let myLabel = #"aria-hidden"
let myNumber = #7
```
```js
var myColor = "red";
var myLabel = "aria-hidden";
var myNumber = 7;
```
**Take a look at the output**. Poly variants are _great_ for JavaScript interop. For example, you can use it to model JavaScript string and number enums like TypeScript, but without confusing their accidental usage with regular strings and numbers.
`myColor` uses the common syntax. The second and third syntaxes are to support expressing strings and numbers more conveniently. We allow the second one because otherwise it'd be invalid syntax since symbols like `-` and others are usually reserved.
## Type Declaration
Although **optional**, you can still pre-declare a poly variant type:
```res
// Note the surrounding square brackets, and # for constructors
type color = [#red | #green | #blue]
```
These types can also be inlined, unlike for regular variant:
```res
let render = (myColor: [#red | #green | #blue]) => {
switch myColor {
| #blue => Console.log("Hello blue!")
| #red
| #green => Console.log("Hello other colors")
}
}
```
```js
function render(myColor) {
if (myColor === "green" || myColor === "red") {
console.log("Hello other colors");
} else {
console.log("Hello blue!");
}
}
```
**Note**: because a poly variant value's type definition is **inferred** and not searched in the scope, the following snippet won't error:
```res
type color = [#red | #green | #blue]
let render = myColor => {
switch myColor {
| #blue => Console.log("Hello blue!")
| #green => Console.log("Hello green!")
// works!
| #yellow => Console.log("Hello yellow!")
}
}
```
```js
function render(myColor) {
if (myColor === "yellow") {
console.log("Hello yellow!");
} else if (myColor === "green") {
console.log("Hello green!");
} else {
console.log("Hello blue!");
}
}
```
That `myColor` parameter's type is inferred to be `#red`, `#green` or `#yellow`, and is unrelated to the `color` type. If you intended `myColor` to be of type `color`, annotate it as `myColor: color` in any of the places.
## Constructor Arguments
This is similar to a regular variant's [constructor arguments](variant#constructor-arguments):
```res
type account = [
| #Anonymous
| #Instagram(string)
| #Facebook(string, int)
]
let me: account = #Instagram("Jenny")
let him: account = #Facebook("Josh", 26)
```
```js
var me = {
NAME: "Instagram",
VAL: "Jenny"
};
var him = {
NAME: "Facebook",
VAL: [
"Josh",
26
]
};
```
### Combine Types and Pattern Match
You can use poly variant types within other poly variant types to create a sum of all constructors:
```res
type red = [#Ruby | #Redwood | #Rust]
type blue = [#Sapphire | #Neon | #Navy]
// Contains all constructors of red and blue.
// Also adds #Papayawhip
type color = [red | blue | #Papayawhip]
let myColor: color = #Ruby
```
```js
var myColor = "Ruby";
```
There's also some special [pattern matching](./pattern-matching-destructuring) syntax to match on constructors defined in a specific poly variant type:
```res
// Continuing the previous example above...
switch myColor {
| #...blue => Console.log("This blue-ish")
| #...red => Console.log("This red-ish")
| other => Console.log2("Other color than red and blue: ", other)
}
```
```js
var other = myColor;
if (other === "Neon" || other === "Navy" || other === "Sapphire") {
console.log("This is blue-ish");
} else if (other === "Rust" || other === "Ruby" || other === "Redwood") {
console.log("This is red-ish");
} else {
console.log("Other color than red and blue: ", other);
}
```
This is a shorter version of:
```res
switch myColor {
| #Sapphire | #Neon | #Navy => Console.log("This is blue-ish")
| #Ruby | #Redwood | #Rust => Console.log("This is red-ish")
| other => Console.log2("Other color than red and blue: ", other)
}
```
## Structural Sharing
Since poly variants value don't have a source of truth for their type, you can write such code:
```res
type preferredColors = [#white | #blue]
let myColor: preferredColors = #blue
let displayColor = v => {
switch v {
| #red => "Hello red"
| #green => "Hello green"
| #white => "Hey white!"
| #blue => "Hey blue!"
}
}
Console.log(displayColor(myColor))
```
```js
var myColor = "blue";
function displayColor(v) {
if (v === "white") {
return "Hey white!";
} else if (v === "red") {
return "Hello red";
} else if (v === "green") {
return "Hello green";
} else {
return "Hey blue!";
}
}
console.log(displayColor("blue"));
```
With a regular variant, the line `displayColor(myColor)` would fail, since it'd complain that the type of `myColor` doesn't match the type of `v`. No problem with poly variant.
## JavaScript Output
Poly variants are great for JavaScript interop! You can share their values to JS code, or model incoming JS values as poly variants.
- `#red` and `#"I am red 😃"` compile to JavaScipt `"red"` and `"I am red 😃"`.
- `#1` compiles to JavaScript `1`.
- Poly variant constructor with 1 argument, like `Instagram("Jenny")` compile to a straightforward `{NAME: "Instagram", VAL: "Jenny"}`. 2 or more arguments like `#Facebook("Josh", 26)` compile to a similar object, but with `VAL` being an array of the arguments.
### Bind to Functions
For example, let's assume we want to bind to `Intl.NumberFormat` and want to make sure that our users only pass valid locales, we could define an external binding like this:
```res
type t
@scope("Intl") @val
external makeNumberFormat: ([#"de-DE" | #"en-GB" | #"en-US"]) => t = "NumberFormat"
let intl = makeNumberFormat(#"de-DE")
```
```js
var intl = Intl.NumberFormat("de-DE");
```
The JS output is identical to handwritten JS, but we also get to enjoy type errors if we accidentally write `makeNumberFormat(#"de-DR")`.
More advanced usage examples for poly variant interop can be found in [Bind to JS Function](bind-to-js-function#constrain-arguments-better).
### Bind to String Enums
Let's assume we have a TypeScript module that expresses following enum export:
```js
// direction.js
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
export const myDirection = Direction.Up
```
For this particular example, we can also inline poly variant type definitions to design the type for the imported `myDirection` value:
```res
type direction = [ #UP | #DOWN | #LEFT | #RIGHT ]
@module("./direction.js") external myDirection: direction = "myDirection"
```
```js
var DirectionJs = require("./direction.js");
var myDirection = DirectionJs.myDirection;
```
Again: since we were using poly variants, the JS Output is practically zero-cost and doesn't add any extra code!
## Extra Constraints on Types
The previous poly variant type annotations we've looked at are the regular "closed" kind. However, there's a way to express "I want at least these constructors" (lower bound) and "I want at most these constructors" (upper bound):
```res
// Only #Red allowed. Closed.
let basic: [#Red] = #Red
// May contain #Red, or any other value. Open
// here, foreground will actually be inferred as [> #Red | #Green]
let foreground: [> #Red] = #Green
// The value must be, at most, one of #Red or #Blue
// Only #Red and #Blue are valid values
let background: [< #Red | #Blue] = #Red
```
**Note:** We added this info for educational purposes. In most cases you will not want to use any of this stuff, since it makes your APIs pretty unreadable / hard to use.
### Closed `[`
This is the simplest poly variant definition, and also the most practical one. Like a common variant type, this one defines an exact set of constructors.
```res
type rgb = [ #Red | #Green | #Blue ]
let color: rgb = #Green
```
In the example above, `color` will only allow one of the three constructors that are defined in the `rgb` type. This is usually the way how poly variants should be defined.
In case you want to define a type that is extensible, you'll need to use the lower / upper bound syntax.
### Lower Bound `[>`
A lower bound defines the minimum set of constructors a poly variant type is aware of. It is also considered an "open poly variant type", because it doesn't restrict any additional values.
Here is an example on how to make a minimum set of `basicBlueTones` extensible for a new `color` type:
```res
type basicBlueTone<'a> = [> #Blue | #DeepBlue | #LightBlue ] as 'a
type color = basicBlueTone<[#Blue | #DeepBlue | #LightBlue | #Purple]>
let color: color = #Purple
// This will fail due to missing minimum constructors:
type notWorking = basicBlueTone<[#Purple]>
```
Here, the compiler will enforce the user to define `#Blue | #DeepBlue | #LightBlue` as the minimum set of constructors when trying to extend `basicBlueTone<'a>`.
**Note:** Since we want to define an extensible poly variant, we need to provide a type placeholder `<'a>`, and also add `as 'a` after the poly variant declaration, which essentially means: "Given type `'a` is constraint to the minimum set of constructors (`#Blue | #DeepBlue | #LightBlue`) defined in `basicBlueTone`".
### Upper Bound `[<`
The upper bound works in the opposite way than a lower bound: the extending type may only use constructors that are stated in the upper bound constraint.
Here another example, but with red colors:
```res
type validRed<'a> = [< #Fire | #Crimson | #Ash] as 'a
type myReds = validRed<[#Ash]>
// This will fail due to unlisted constructor not defined by the lower bound
type notWorking = validRed<[#Purple]>
```
## Coercion
You can convert a poly variant to a `string` or `int` at no cost:
```res
type company = [#Apple | #Facebook]
let theCompany: company = #Apple
let message = "Hello " ++ (theCompany :> string)
```
```js
var theCompany = "Apple";
var message = "Hello " + theCompany;
```
**Note**: for the coercion to work, the poly variant type needs to be closed; you'd need to annotate it, since otherwise, `theCompany` would be inferred as `[> #Apple]`.
## Tips & Tricks
### Variant vs Polymorphic Variant
One might think that polymorphic variants are superior to regular [variants](./variant). As always, there are trade-offs:
- Due to their "structural" nature, poly variant's type errors might be more confusing. If you accidentally write `#blur` instead of `#blue`, ReScript will still error but can't indicate the correct source as easily. Regular variants' source of truth is the type definition, so the error can't go wrong.
- It's also harder to refactor poly variants. Consider this:
```res
let myFruit = #Apple
let mySecondFruit = #Apple
let myCompany = #Apple
```
Refactoring the first one to `#Orange` doesn't mean we should refactor the third one. Therefore, the editor plugin can't touch the second one either. Regular variant doesn't have such problem, as these 2 values presumably come from different variant type definitions.
- You might lose some nice pattern match checks from the compiler:
```res
let myColor = #red
switch myColor {
| #red => Console.log("Hello red!")
| #blue => Console.log("Hello blue!")
}
```
Because there's no poly variant definition, it's hard to know whether the `#blue` case can be safely removed.
In most scenarios, we'd recommend to use regular variants over polymorphic variants, especially when you are writing plain ReScript code. In case you want to write zero-cost interop bindings or generate clean JS output, poly variants are oftentimes a better option.
---
title: "Primitive Types"
description: "Primitive Data Types in ReScript"
canonical: "/docs/manual/v11.0.0/primitive-types"
---
# Primitive Types
ReScript comes with the familiar primitive types like `string`, `int`, `float`, etc.
## String
ReScript `string`s are delimited using **double** quotes (single quotes are reserved for the character type below).
```res example
let greeting = "Hello world!"
let multilineGreeting = "Hello
world!"
```
```js
var greeting = "Hello world!";
var multilineGreeting = "Hello\n world!";
```
To concatenate strings, use `++`:
```res example
let greetings = "Hello " ++ "world!"
```
```js
var greetings = "Hello world!";
```
### String Interpolation
There's a special syntax for string that allows
- multiline string just like before
- no special character escaping
- Interpolation
```res example
let name = "Joe"
let greeting = `Hello
World
👋
${name}
`
```
```js
var name = "Joe";
var greeting = "Hello\nWorld\n👋\n" + name + "\n";
```
This is just like JavaScript's backtick string interpolation, except without needing to escape special characters.
### Usage
See the familiar `String` API in the [API docs](api/core/string). Since a ReScript string maps to a JavaScript string, you can mix & match the string operations in all standard libraries.
### Tips & Tricks
**You have a good type system now!** In an untyped language, you'd often overload the meaning of string by using it as:
- a unique id: `var BLUE_COLOR = "blue"`
- an identifier into a data structure: `var BLUE = "blue" var RED = "red" var colors = [BLUE, RED]`
- the name of an object field: `person["age"] = 24`
- an enum: `if (audio.canPlayType() === 'probably') {...}` [(ಠ_ಠ)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType#Return_value)
- other crazy patterns you'll soon find horrible, after getting used to ReScript's alternatives.
The more you overload the poor string type, the less the type system (or a teammate) can help you! ReScript provides concise, fast and maintainable types & data structures alternatives to the use-cases above (e.g. variants, in a later section).
## Char
ReScript has a type for a string with a single letter:
```res example
let firstLetterOfAlphabet = 'a'
```
```js
var firstLetterOfAlphabet = /* "a" */97;
```
**Note**: Char doesn't support Unicode or UTF-8 and is therefore not recommended.
To convert a String to a Char, use `String.get("a", 0)`. To convert a Char to a String, use `String.make(1, 'a')`.
## Regular Expression
ReScript regular expressions compile cleanly to their JavaScript counterpart:
```res example
let r = %re("/b/g")
```
```js
var r = /b/g;
```
A regular expression like the above has the type `Re.t`. The [RegExp](api/core/regexp) module contains the regular expression helpers you have seen in JS.
## Boolean
A ReScript boolean has the type `bool` and can be either `true` or `false`. Common operations:
- `&&`: logical and.
- `||`: logical or.
- `!`: logical not.
- `<=`, `>=`, `<`, `>`
- `==`: structural equal, compares data structures deeply. `(1, 2) == (1, 2)` is `true`. Convenient, but use with caution.
- `===`: referential equal, compares shallowly. `(1, 2) === (1, 2)` is `false`. `let myTuple = (1, 2); myTuple === myTuple` is `true`.
- `!=`: structural unequal.
- `!==`: referential unequal.
ReScript's `true/false` compiles into a JavaScript `true/false`.
## Integers
32-bits, truncated when necessary. We provide the usual operations on them: `+`, `-`, `*`, `/`, etc. See [Int](api/core/int) for helper functions.
**Be careful when you bind to JavaScript numbers!** Since ReScript integers have a much smaller range than JavaScript numbers, data might get lost when dealing with large numbers. In those cases it’s much safer to bind the numbers as **float**. Be extra mindful of this when binding to JavaScript Dates and their epoch time.
To improve readability, you may place underscores in the middle of numeric literals such as `1_000_000`. Note that underscores can be placed anywhere within a number, not just every three digits.
## Floats
Float requires other operators: `+.`, `-.`, `*.`, `/.`, etc. Like `0.5 +. 0.6`. See [Float](api/core/float) for helper functions.
As with integers, you may use underscores within literals to improve readability.
### Int-to-Float Coercion
`int` values can be coerced to `float` with the `:>` (type coercion) operator.
```res example
let result = (1 :> float) +. 2.
```
```js
var result = 1 + 2;
```
## Big Integers (experimental)
**Since 11.1**
For values which are too large to be represented by Int or Float, there is the `bigint` primitive type.
We provide the usual operations on them: `+`, `-`, `*`, `/`, etc. See [BigInt](api/core/bigint) for helper functions.
A `bigint` number is denoted by a trailing `n` like so: `42n`.
As `bigint` is a different data type than `int`, it's necessary to open the corresponding module to overload the operators.
```res example
open! BigInt
let a = 9007199254740991n + 9007199254740991n
let b = 2n ** 2n
```
```js
var a = 9007199254740991n + 9007199254740991n;
var p = 2n ** 2n;
```
It also supports all the bitwise operations, except unsigned shift right (`>>>`), which is not supported by JS itself for `bigint`s.
```res example
open! BigInt
let a = land(1n, 1n)
let b = lor(1n, 1n)
let c = lxor(1n, 1n)
let d = lnot(1n)
let e = lsl(1n, 1n)
let f = asr(1n, 1n)
```
```js
var Js_bigint = require("./stdlib/js_bigint.js");
var a = 1n & 1n;
var b = 1n | 1n;
var c = 1n ^ 1n;
var d = Js_bigint.lnot(1n);
var e = (1n << 1n);
var f = (1n >> 1n);
```
It can also be pattern-matched.
```res example
let bigintValue = 1n
switch bigintValue {
| 1n => Console.log("Small bigint")
| 100n => Console.log("Larger bigint")
| _ => Console.log("Other bigint")
}
```
```js
if (1n !== 1n) {
if (1n !== 100n) {
console.log("Other bigint");
} else {
console.log("Larger bigint");
}
} else {
console.log("Small bigint");
}
var bigintValue = 1n;
```
## Unit
The `unit` type indicates the absence of a specific value. It has only a single value, `()`, which acts as a placeholder when no other value exists or is needed. It compiles to JavaScript's `undefined` and resembles the `void` type in languages such as C++. What's the point of such a type?
Consider the `Math.random` function. Its type signature is `unit => float`, which means it receives a `unit` as input and calculates a random `float` as output. You use the function like this - `let x = Math.random()`. Notice `()` as the first and only function argument.
Imagine a simplified `Console.log` function that prints a message. Its type signature is `string => unit` and you'd use it like this `Console.log("Hello!")`. It takes a string as input, prints it, and then returns nothing useful. When `unit` is the output of a function it means the function performs some kind of side-effect.
## Unknown
The `unknown` type represents values with contents that are a mystery or are not 100% guaranteed to be what you think they are. It provides type-safety when interacting with data received from an untrusted source. For example, suppose an external function is supposed to return a `string`. It might. But if the documentation is not accurate or the code has bugs, the function could return `null`, an `array`, or something else you weren't expecting.
The ReScript type system helps you avoid run-time crashes and unpredicatable behavior by preventing you from using `unknown` in places that expect a `string` or `int` or some other type. The ReScript core libraries also provide utility functions to help you inspect `unknown` values and access their contents. In some cases you may need a JSON parsing library to convert `unknown` values to types you can safely use.
Consider using `unknown` when receiving data from [external JavaScript functions](/docs/manual/latest/bind-to-js-function)
---
title: "Project Structure"
description: "Notes on project structure and other rough ReScript guidelines"
canonical: "/docs/manual/v11.0.0/project-structure"
---
# Project Structure
These are the existing, non-codified community practices that are currently propagated through informal agreement. We might remove some of them at one point, and enforce some others. Right now, they're just recommendations for ease of newcomers.
## File Casing
Capitalized file names (aka first letter upper-cased).
**Justification**: Module names can only be capitalized. Newcomers often ask how a file maps to a module, and why `draw.res` maps to the module `Draw`, and sometimes try to refer to a module through uncapitalized identifiers. Using `Draw.res` makes this mapping more straightforward. It also helps certain file names that'd be awkward in uncapitalized form: `uRI.res`.
## Ignore `.merlin` File
This is generated by the build system and you should not have to manually edit it. Don't check it into the repo.
**Justification**: `.merlin` is for editor tooling. The file contains absolute paths, which are also not cross-platform (e.g. Windows paths are different).
## Folders
Try not to have too many nested folders. Keep your project flat, and have fewer files (reminder: you can use nested modules).
**Justification**: The file system is a _tree_, but your code's dependencies are a _graph_. Because of that, any file & folder organization is usually imperfect. While it's still valuable to group related files together in a folder, the time wasted debating & getting decision paralysis over these far outweight their benefits. We'll always recommend you to Get Work Done instead of debating about these issues.
## Third-party Dependencies
Keep them to a minimum.
**Justification**: A compiled, statically typed language cannot model its dependencies easily by muddling along like in a dynamic language, especially when we're still piggy-backing on NPM/Yarn (to reduce learning overhead in the medium-term). Keeping dependencies simple & lean helps reduce possibility of conflicts (e.g. two diamond dependencies, or clashing interfaces).
## Documentation
Have them. Spend more effort making them great (examples, pitfalls) and professional rather than _just_ fancy-looking. Do use examples, and avoid using names such as `foo` and `bar`. There's always more concrete names (it's an example, no need to be abstract/generalized just yet. The API docs will do this plentily). For blog posts, don't repeat the docs themselves, describe the _transition_ from old to new, and why (e.g. "it was a component, now it's a function, because ...").
**Justification**: It's hard for newcomers to distinguish between a simple/decent library and one that's fancy-looking. For the sake of the community, don't try too hard to one-up each other's libraries. Do spread the words, but use your judgement too.
## PPX & Other Meta-tools
Keep them to a minimum. PPX, unless used in renown cases (printer, accessors and serializer/deserializer generation), can cause big learning churn for newcomers; on top of the syntax, semantics, types, build tool & FFI that they already have to learn, learning per-library custom transformations of the code is an extra step. More invasive macros makes the code itself less semantically meaningful too, since the essence would be hiding somewhere else.
## Paradigm
Don't abuse overly fancy features. Do leave some breathing room for future APIs but don't over-architect things.
**Justification**: Simple code helps newcomers understand and potentially contribute to your code. Contributing is the best way for them to learn. The extra help you receive might also surpass the gain of using a slightly more clever language trick. But do try new language tricks in some of more casual projects! You might discover new ways of architecting code.
## Publishing
If it's a wrapper for a JS library, don't publish the JS artifacts. If it's a legit library, publish the artifacts in lib/js if you think JS consumers might use it. This is especially the case when you gradually convert a JS lib to ReScript while not breaking existing JS consumers.
Do put the keywords `"rescript"` in your package.json `keywords` field. This allows us to find the library much more easily for future purposes.
**Justification**: Be nice to JS consumers of your library. They're your future ReScripters.
---
title: "Promises"
description: "JS Promise handling in ReScript"
canonical: "/docs/manual/v11.0.0/promise"
---
# Promise
> **Note:** Starting from ReScript 10.1 and above, we recommend using [async / await](./async-await) when interacting with Promises.
## `promise` type
**Since 10.1**
In ReScript, every JS promise is represented with the globally available `promise<'a>` type. For ReScript versions < 10.1, use its original alias `Js.Promise.t<'a>` instead.
Here's a usage example in a function signature:
```resi
// User.resi file
type user = {name: string}
let fetchUser: string => promise
```
To work with promise values (instead of using `async` / `await`) you may want to use the built-in `Promise` module.
## Promise
A builtin module to create, chain and manipulate promises.
### Creating a promise
```res
let p1 = Promise.make((resolve, reject) => {
// We use uncurried functions for resolve / reject
// for cleaner JS output without unintended curry calls
resolve("hello world")
})
let p2 = Promise.resolve("some value")
// You can only reject `exn` values for streamlined catch handling
exception MyOwnError(string)
let p3 = Promise.reject(MyOwnError("some rejection"))
```
### Access the contents and transform a promise
```res
let logAsyncMessage = () => {
open Promise
Promise.resolve("hello world")
->then(msg => {
// then callbacks require the result to be resolved explicitly
resolve("Message: " ++ msg)
})
->then(msg => {
Console.log(msg)
// Even if there is no result, we need to use resolve() to return a promise
resolve()
})
->ignore // Requires ignoring due to unhandled return value
}
```
For comparison, the `async` / `await` version of the same code would look like this:
```res
let logAsyncMessage = async () => {
let msg = await Promise.resolve("hello world")
Console.log(`Message: ${msg}`)
}
```
Needless to say, the async / await version offers better ergonomics and less opportunities to run into type issues.
### Handling Rejected Promises
You can handle a rejected promise using the [`Promise.catch()`](./api/core/promise#value-catch) method, which allows you to catch and manage errors effectively.
### Run multiple promises in parallel
In case you want to launch multiple promises in parallel, use `Promise.all`:
```res
@val
external fetchMessage: string => promise = "global.fetchMessage"
let logAsyncMessage = async () => {
let messages = await Promise.all([fetchMessage("message1"), fetchMessage("message2")])
Console.log(messages->Array.joinWith(", "))
}
```
```js
async function logAsyncMessage(param) {
var messages = await Promise.all([
global.fetchMessage("message1"),
global.fetchMessage("message2")
]);
console.log(messages.join(", "));
}
export {
logAsyncMessage ,
}
```
## Js.Promise module (legacy - do not use)
> **Note:** The `Js.Promise` bindings are following the outdated data-last convention from a few years ago. We kept those APIs for backwards compatibility. Either use [`Promise`](api/core/promise) or a third-party promise binding instead.
ReScript has built-in support for [JavaScript promises](api/js/promise). The 3 functions you generally need are:
- `Js.Promise.resolve: 'a => Js.Promise.t<'a>`
- `Js.Promise.then_: ('a => Js.Promise.t<'b>, Js.Promise.t<'a>) => Js.Promise.t<'b>`
- `Js.Promise.catch: (Js.Promise.error => Js.Promise.t<'a>, Js.Promise.t<'a>) => Js.Promise.t<'a>`
Additionally, here's the type signature for creating a promise on the ReScript side:
```res
Js.Promise.make: (
(
~resolve: (. 'a) => unit,
~reject: (. exn) => unit
) => unit
) => Js.Promise.t<'a>
```
This type signature means that `make` takes a callback that takes 2 named arguments, `resolve` and `reject`. Both arguments are themselves [uncurried callbacks](
function.md#uncurried-function) (with a dot). `make` returns the created promise.
### Usage
Using the [pipe operator](pipe.md):
```res example
let myPromise = Js.Promise.make((~resolve, ~reject) => resolve(. 2))
myPromise->Js.Promise.then_(value => {
Console.log(value)
Js.Promise.resolve(value + 2)
}, _)->Js.Promise.then_(value => {
Console.log(value)
Js.Promise.resolve(value + 3)
}, _)->Js.Promise.catch(err => {
Console.log2("Failure!!", err)
Js.Promise.resolve(-2)
}, _)
```
```js
var myPromise = new Promise(function (resolve, reject) {
return resolve(2);
});
myPromise
.then(function (value) {
console.log(value);
return Promise.resolve((value + 2) | 0);
})
.then(function (value) {
console.log(value);
return Promise.resolve((value + 3) | 0);
})
.catch(function (err) {
console.log("Failure!!", err);
return Promise.resolve(-2);
});
```
---
title: "Record"
description: "Record types in ReScript"
canonical: "/docs/manual/v11.0.0/record"
---
# Record
Records are like JavaScript objects but:
- are immutable by default
- have fixed fields (not extensible)
## Type Declaration
A record needs a mandatory type declaration:
```res prelude
type person = {
age: int,
name: string,
}
```
```js
// Empty output
```
## Creation
To create a `person` record (declared above):
```res prelude
let me = {
age: 5,
name: "Big ReScript"
}
```
```js
var me = {
age: 5,
name: "Big ReScript"
};
```
When you create a new record value, ReScript tries to find a record type declaration that conforms to the shape of the value. So the `me` value here is inferred as of type `person`.
The type is found by looking above the `me` value. **Note**: if the type instead resides in another file or module, you need to explicitly indicate which file or module it is:
```res example
// School.res
type person = {age: int, name: string}
```
```js
// Empty output
```
```res
// Example.res
let me: School.person = {age: 20, name: "Big ReScript"}
/* or */
let me2 = {School.age: 20, name: "Big ReScript"}
```
```js
var me = {
age: 20,
name: "Big ReScript"
};
var me2 = {
age: 20,
name: "Big ReScript"
};
```
In both `me` and `me2` the record definition from `School` is found. The first one, `me` with the regular type annotation, is preferred.
## Access
Use the familiar dot notation:
```res example
let name = me.name
```
```js
var name = "Big ReScript";
```
## Immutable Update
New records can be created from old records with the `...` spread operator. The original record isn't mutated.
```res example
let meNextYear = {...me, age: me.age + 1}
```
```js
var meNextYear = {
age: 21,
name: "Big ReScript"
};
```
**Note**: spread cannot add new fields to the record value, as a record's shape is fixed by its type.
## Mutable Update
Record fields can optionally be mutable. This allows you to efficiently update those fields in-place with the `=` operator.
```res example
type person = {
name: string,
mutable age: int
}
let baby = {name: "Baby ReScript", age: 5}
baby.age = baby.age + 1 // `baby.age` is now 6. Happy birthday!
```
```js
var baby = {
name: "Baby ReScript",
age: 5
};
baby.age = baby.age + 1 | 0;
```
Fields not marked with `mutable` in the type declaration cannot be mutated.
## JavaScript Output
ReScript records compile to straightforward JavaScript objects; see the various JS output tabs above.
## Optional Record Fields
ReScript [`v10`](/blog/release-10-0-0#experimental-optional-record-fields) introduced optional record fields. This means that you can define fields that can be omitted when creating the record. It looks like this:
```res example
type person = {
age: int,
name?: string
}
```
```js
// Empty output
```
Notice how `name` has a suffixed `?`. That means that the field itself is _optional_.
### Creation
You can omit any optional fields when creating a record. Not setting an optional field will default the field's value to `None`:
```res example
type person = {
age: int,
name?: string
}
let me = {
age: 5,
name: "Big ReScript"
}
let friend = {
age: 7
}
```
```js
var me = {
age: 5,
name: "Big ReScript"
};
var friend = {
age: 7
};
```
This has consequences for pattern matching, which we'll expand a bit on soon.
## Immutable Update
Updating an optional field via an immutable update above lets you set that field value without needing to care whether it's optional or not.
```res example
type person = {
age: int,
name?: string
}
let me = {
age: 123,
name: "Hello"
}
let withoutName = {
...me,
name: "New Name"
}
```
```js
import * as Caml_obj from "./stdlib/caml_obj.js";
var me = {
age: 123,
name: "Hello"
};
var newrecord = Caml_obj.obj_dup(me);
newrecord.name = "New Name";
var withoutName = newrecord;
```
However, if you want to set the field to an optional value, you prefix that value with `?`:
```res example
type person = {
age: int,
name?: string
}
let me = {
age: 123,
name: "Hello"
}
let maybeName = Some("My Name")
let withoutName = {
...me,
name: ?maybeName
}
```
```js
import * as Caml_obj from "./stdlib/caml_obj.js";
var me = {
age: 123,
name: "Hello"
};
var maybeName = "My Name";
var newrecord = Caml_obj.obj_dup(me);
newrecord.name = maybeName;
var withoutName = newrecord;
```
You can unset an optional field's value via that same mechanism by setting it to `?None`.
### Pattern Matching on Optional Fields
[Pattern matching](pattern-matching-destructuring), one of ReScript's most important features, has two caveats when you deal with optional fields.
When matching on the value directly, it's an `option`. Example:
```res
type person = {
age: int,
name?: string,
}
let me = {
age: 123,
name: "Hello",
}
let isRescript = switch me.name {
| Some("ReScript") => true
| Some(_) | None => false
}
```
```js
var isRescript;
isRescript = "Hello" === "ReScript" ? true : false;
var me = {
age: 123,
name: "Hello"
};
```
But, when matching on the field as part of the general record structure, it's treated as the underlying, non-optional value:
```res
type person = {
age: int,
name?: string,
}
let me = {
age: 123,
name: "Hello",
}
let isRescript = switch me {
| {name: "ReScript"} => true
| _ => false
}
```
```js
var isRescript;
isRescript = "Hello" === "ReScript" ? true : false;
var me = {
age: 123,
name: "Hello"
};
```
Sometimes you _do_ want to know whether the field was set or not. You can tell the pattern matching engine about that by prefixing your option match with `?`, like this:
```res
type person = {
age: int,
name?: string,
}
let me = {
age: 123,
name: "Hello",
}
let nameWasSet = switch me {
| {name: ?None} => false
| {name: ?Some(_)} => true
}
```
```js
var nameWasSet = true;
var me = {
age: 123,
name: "Hello"
};
```
## Record Type Spread
In ReScript v11, you can now spread one or more record types into a new record type. It looks like this:
```rescript
type a = {
id: string,
name: string,
}
type b = {
age: int
}
type c = {
...a,
...b,
active: bool
}
```
`type c` will now be:
```rescript
type c = {
id: string,
name: string,
age: int,
active: bool,
}
```
Record type spreads act as a 'copy-paste' mechanism for fields from one or more records into a new record. This operation inlines the fields from the spread records directly into the new record definition, while preserving their original properties, such as whether they are optional or mandatory. It's important to note that duplicate field names are not allowed across the records being spread, even if the fields have the same type.
## Record Type Coercion
Record type coercion gives us more flexibility when passing around records in our application code. In other words, we can now coerce a record `a` to be treated as a record `b` at the type level, as long as the original record `a` contains the same set of fields in `b`. Here's an example:
```rescript
type a = {
name: string,
age: int,
}
type b = {
name: string,
age: int,
}
let nameFromB = (b: b) => b.name
let a: a = {
name: "Name",
age: 35,
}
let name = nameFromB(a :> b)
```
Notice how we _coerced_ the value `a` to type `b` using the coercion operator `:>`. This works because they have the same record fields. This is purely at the type level, and does not involve any runtime operations.
Additionally, we can also coerce records from `a` to `b` whenever `a` is a super-set of `b` (i.e. `a` containing all the fields of `b`, and more). The same example as above, slightly altered:
```rescript
type a = {
id: string,
name: string,
age: int,
active: bool,
}
type b = {
name: string,
age: int,
}
let nameFromB = (b: b) => b.name
let a: a = {
id: "1",
name: "Name",
age: 35,
active: true,
}
let name = nameFromB(a :> b)
```
Notice how `a` now has more fields than `b`, but we can still coerce `a` to `b` because `b` has a subset of the fields of `a`.
In combination with [optional record fields](/docs/manual/latest/record#optional-record-fields), one may coerce a mandatory field of an `option` type to an optional field:
```rescript
type a = {
name: string,
// mandatory, but explicitly typed as option
age: option,
}
type b = {
name: string,
// optional field
age?: int,
}
let nameFromB = (b: b) => b.name
let a: a = {
name: "Name",
age: Some(35),
}
let name = nameFromB(a :> b)
```
## Tips & Tricks
### Record Types Are Found By Field Name
With records, you **cannot** say "I'd like this function to take any record type, as long as they have the field `age`". The following **won't work as intended**:
```res
type person = {age: int, name: string}
type monster = {age: int, hasTentacles: bool}
let getAge = (entity) => entity.age
```
```js
function getAge(entity) {
return entity.age;
}
```
Instead, `getAge` will infer that the parameter `entity` must be of type `monster`, the closest record type with the field `age`. The following code's last line fails:
```res
let kraken = {age: 9999, hasTentacles: true}
let me = {age: 5, name: "Baby ReScript"}
getAge(kraken)
getAge(me) // type error!
```
The type system will complain that `me` is a `person`, and that `getAge` only works on `monster`. If you need such capability, use ReScript objects, described [here](object.md).
### Optional Fields in Records Can Be Useful for Bindings
Many JavaScript APIs tend to have large configuration objects that can be a bit annoying to model as records, since you previously always needed to specify all record fields when creating a record.
Optional record fields, introduced in [`v10`](/blog/release-10-0-0#experimental-optional-record-fields), is intended to help with this. Optional fields will let you avoid having to specify all fields, and let you just specify the one's you care about. A significant improvement in ergonomics for bindings and other APIs with for example large configuration objects.
## Design Decisions
After reading the constraints in the previous sections, and if you're coming from a dynamic language background, you might be wondering why one would bother with record in the first place instead of straight using object, since the former needs explicit typing and doesn't allow different records with the same field name to be passed to the same function, etc.
1. The truth is that most of the times in your app, your data's shape is actually fixed, and if it's not, it can potentially be better represented as a combination of variant (introduced next) + record instead.
2. Since a record type is resolved through finding that single explicit type declaration (we call this "nominal typing"), the type error messages end up better than the counterpart ("structural typing", like for tuples). This makes refactoring easier; changing a record type's fields naturally allows the compiler to know that it's still the same record, just misused in some places. Otherwise, under structural typing, it might get hard to tell whether the definition site or the usage site is wrong.
---
title: "Reserved Keywords"
description: "All reserved keywords in ReScript"
canonical: "/docs/manual/v11.0.0/reserved-keywords"
---
# Reserved Keywords
> **Note**: Some of these words are reserved purely for backward compatibility.
>
> If you _need_ to use one of these names as binding and/or field name, see [Use Illegal Identifier Names](use-illegal-identifier-names.md).
- `and`
- `as`
- `assert`
- `constraint`
- `else`
- `exception`
- `external`
* `false`
* `for`
- `if`
- `in`
- `include`
* `lazy`
* `let`
- `module`
- `mutable`
- `of`
- `open`
- `rec`
- `switch`
- `true`
- `try`
- `type`
- `when`
- `while`
- `with`
---
title: "Scoped Polymorphic Types"
description: "Scoped Polymorphic Types in ReScript"
canonical: "/docs/manual/v11.0.0/scoped-polymorphic-types"
---
# Scoped Polymorphic Types
Scoped Polymorphic Types in ReScript are functions with the capability to handle arguments of any type within a specific scope. This feature is particularly valuable when working with JavaScript APIs, as it allows your functions to accommodate diverse data types while preserving ReScript's strong type checking.
## Definition and Usage
Scoped polymorphic types in ReScript offer a flexible and type-safe way to handle diverse data types within specific scopes. This documentation provides an example to illustrate their usage in a JavaScript context.
### Example: Logging API
Consider a logging example within a JavaScript context that processes various data types:
```js
const logger = {
log: (data) => {
if (typeof data === "string") {
/* handle string */
} else if (typeof data === "number") {
/* handle number */
} else {
/* handle other types */
}
},
};
```
In ReScript, we can bind to this function as a record with a scoped polymorphic function type:
```res prelude
type logger = { log: 'a. 'a => unit }
@module("jsAPI") external getLogger: unit => logger = "getLogger"
```
The `logger` type represents a record with a single field `log`, which is a scoped polymorphic function type `'a. 'a => unit`. The `'a` indicates a type variable that can be any type within the scope of the `log` function.
Now, we can utilize the function obtained from `getLogger`:
```res example
let myLogger = getLogger()
myLogger.log("Hello, ReScript!")
myLogger.log(42)
```
```js
var myLogger = JsAPI.getLogger();
myLogger.log("Hello, ReScript!");
myLogger.log(42);
```
In this example, we create an instance of the logger by calling `getLogger()`, and then we can use the `log` function on the `myLogger` object to handle different data types.
## Limitations of Normal Polymorphic Types
Let's consider the same logging example in ReScript, but this time using normal polymorphic types:
```res
type logger<'a> = { log: 'a => unit}
@module("jsAPI") external getLogger: unit => logger<'a> = "getLogger"
```
In this case, the `logger` type is a simple polymorphic function type `'a => unit`. However, when we attempt to use this type in the same way as before, we encounter an issue:
```res
let myLogger = getLogger()
myLogger.log("Hello, ReScript!")
myLogger.log(42) // Type error!
```
The problem arises because the type inference in ReScript assigns a concrete type to the `logger` function based on the first usage. In this example, after the first call to `myLogger`, the compiler infers the type `logger` for `myLogger`. Consequently, when we attempt to pass an argument of type `number` in the next line, a type error occurs because it conflicts with the inferred type `logger`.
In contrast, scoped polymorphic types, such as `'a. 'a => unit`, overcome this limitation by allowing type variables within the scope of the function. They ensure that the type of the argument is preserved consistently within that scope, regardless of the specific value used in the first invocation.
## Limitations of Scoped Polymorphic Types
Scoped polymorphic types work only when they are directly applied to let-bindings or record fields (as demonstrated in the logger example above). They can neither be applied to function bodies, nor to separate type definitions:
```res
exception Abort
let testExn: 'a. unit => 'a = () => raise(Abort) // Works!
let testExn2 = (): 'a. 'a = raise(Abort) // Syntax error!
type fn = 'a. 'a => unit // Syntax error!
```
---
title: "Shared Data Types"
description: "Data types that share runtime presentation between JS and ReScript"
canonical: "/docs/manual/v11.0.0/shared-data-types"
---
# Shared Data Types
ReScript's built-in values of type `string`, `float`, `array` and a few others have a rather interesting property: they compile to the exact same value in JavaScript!
This means that if you're passing e.g. a ReScript string to the JavaScript side, the JS side can directly use it as a native JS string. It also means that you can import a JS string and pretend it's a native ReScript string.
Unlike most compiled-to-js languages, in ReScript, **you don't need to write data converters back and forth for most of our values**!
**Shared, bidirectionally usable types**:
- String. ReScript strings are JavaScript strings, vice-versa. (Caveat: only our backtick string `` `hello 👋 ${personName}` `` supports unicode and interpolation).
- Float. ReScript floats are JS numbers, vice-versa.
- Array. In addition to the [Array API](api/core/array), we provide our own [Belt.Array](api/belt/array#set) API too.
- Tuple. Compiles to a JS array. You can treat a fixed-sized, heterogenous JS array as ReScript tuple too.
- Boolean.
- Record. Record compiles to JS object. Therefore you can also treat JS objects as records. If they're too dynamic, consider modeling them on the ReScript side as a hashmap/dictionary [`Dict`](api/core/dict) or a ReScript object.
- Object. ReScript objects are JavaScript objects, vice-versa.
- Function. They compile to clean JS functions.
- Module. ReScript files are considered top-level modules, and are compiled to JS files 1 to 1. Nested modules are compiled to JavaScript objects.
- Polymorphic variants.
- Unit. The `unit` type, which has a single value `()`, compiles to `undefined` too. Likewise, you can treat an incoming JS `undefined` as `()` if that's the only value it'll ever be.
**Types that are slightly different than JS, but that you can still use from JS**:
- Int. **Ints are 32-bits**! Be careful, you can potentially treat them as JS numbers and vice-versa, but if the number's large, then you better treat JS numbers as floats. For example, we bind to `Date` using `float`s.
- Option. The `option` type's `None` value compiles into JS `undefined`. The `Some` value, e.g. `Some(5)`, compiles to `5`. Likewise, you can treat an incoming JS `undefined` as `None`. **JS `null` isn't handled here**. If your JS value can be `null`, use [Nullable](api/core/nullable) helpers.
- Exception.
- Variant. Check the compiled JavaScript output of variant to see its shape. We don't recommend exporting a ReScript variant for pure JS usage, since they're harder to read as plain JS code, but you can do it.
- List, which is just a regular variant.
**Non-shared types (aka internal types)**:
- Character.
- Int64.
- Lazy values.
- Everything else.
Many of these are stable, which means that you can still serialize/deserialize them as-is without manual conversions. But we discourage actively peeking into their structure otherwise.
These types require manual conversions if you want to export them for JS consumption. For a seamless JS/TypeScript integration experience, you might want to use [genType](https://github.com/cristianoc/gentype) instead of doing conversions by hand.
---
title: "Tagged templates"
description: "Using tagged templates in ReScript"
canonical: "/docs/manual/v11.0.0/tagged-templates"
---
# Tagged templates
**Since 11.1**
Tagged templates provide a special form of string interpolation, enabling the creation of template literals
where placeholders aren't restricted to strings. Moreover, the resulting output isn't confined solely to
strings either. You can take a look at the [JS documentation
about tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates)
to learn more about them.
## Define a tag function
Tag functions in ReScript have the following signature:
```res
let myTagFunction : (array, array<'param>) => 'output
```
As you can see, you can have any type you want both for the placeholder array and for the output.
Given how string interpolation works, you'll always have the following invariant:
```res
Array.length(strings) == Array.length(placeholder) + 1
```
Let's say you want to interpolate strings with all kind of builtin types and make it work inside React components,
you can define the following tag function:
```res prelude
type params =
| I(int)
| F(float)
| S(string)
| Bool(bool)
let s = (strings, parameters) => {
let text = Array.reduceWithIndex(parameters, Array.getUnsafe(strings, 0), (
acc,
param,
i,
) => {
let s = Array.getUnsafe(strings, i + 1)
let p = switch param {
| I(i) => Int.toString(i)
| F(f) => Float.toString(f)
| S(s) => s
| Bool(true) => "true"
| Bool(false) => "false"
}
acc ++ p ++ s
})
React.string(text)
}
```
```js
import * as Core__Array from "./stdlib/core__Array.js";
function s(strings, parameters) {
return Core__Array.reduceWithIndex(parameters, strings[0], (function (acc, param, i) {
var s = strings[i + 1 | 0];
var p;
switch (param.TAG) {
case "I" :
case "F" :
p = param._0.toString();
break;
case "S" :
p = param._0;
break;
case "Bool" :
p = param._0 ? "true" : "false";
break;
}
return acc + p + s;
}));
}
```
## Write tagged template literals
Now that you have defined your tag function, you can use it this way:
```res example
module Greetings = {
@react.component
let make = (~name, ~age) => {
{s`hello ${S(name)} you're ${I(age)} year old!`}
}
}
```
```js
function Greetings(props) {
return React.createElement("div", undefined, s([
"hello ",
" you're ",
" year old!"
], [
{
TAG: "S",
_0: props.name
},
{
TAG: "I",
_0: props.age
}
]));
}
```
Pretty neat, isn't it? As you can see, it looks like any regular template literal but it accepts placeholders that are not strings
and it outputs something that is not a string either, a `React.element` in this case.
---
title: "Try"
description: "Try ReScript via Command Line"
canonical: "/docs/manual/v11.0.0/try"
---
## Try Online
Our [Playground](/try) lets you try ReScript online, and comes with the [ReScript React bindings](/docs/react/latest/introduction) and the new [ReScript Core](https://github.com/rescript-lang/rescript-core) standard library preinstalled.
---
title: "Tuple"
description: "Tuple types and values in ReScript"
canonical: "/docs/manual/v11.0.0/tuple"
---
# Tuple
Tuples are a ReScript-specific data structure that don't exist in JavaScript. They are:
- immutable
- ordered
- fix-sized at creation time
- heterogeneous (can contain different types of values)
```res example
let ageAndName = (24, "Lil' ReScript")
let my3dCoordinates = (20.0, 30.5, 100.0)
```
```js
var ageAndName = [24, "Lil' ReScript"];
var my3dCoordinates = [20.0, 30.5, 100.0];
```
Tuples' types can be used in type annotations as well. Tuple types visually resemble tuples values.
```res prelude
let ageAndName: (int, string) = (24, "Lil' ReScript")
// a tuple type alias
type coord3d = (float, float, float)
let my3dCoordinates: coord3d = (20.0, 30.5, 100.0)
```
```js
var ageAndName = [24, "Lil' ReScript"];
var my3dCoordinates = [20.0, 30.5, 100.0];
```
**Note**: there's no tuple of size 1. You'd just use the value itself.
## Usage
To get a specific member of a tuple, destructure it:
```res example
let (_, y, _) = my3dCoordinates // now you've retrieved y
```
```js
var y = 30.5;
```
The `_` means you're ignoring the indicated members of the tuple.
Tuples aren't meant to be updated mutatively. You'd create new ones by destructuring the old ones:
```res example
let coordinates1 = (10, 20, 30)
let (c1x, _, _) = coordinates1
let coordinates2 = (c1x + 50, 20, 30)
```
```js
var coordinates1 = [10, 20, 30];
var c1x = 10;
var coordinates2 = [60, 20, 30];
```
## Tips & Tricks
You'd use tuples in handy situations that pass around multiple values without too much ceremony. For example, to return many values:
```res
let getCenterCoordinates = () => {
let x = doSomeOperationsHere()
let y = doSomeMoreOperationsHere()
(x, y)
}
```
```js
function getCenterCoordinates(param) {
var x = doSomeOperationsHere(undefined);
var y = doSomeMoreOperationsHere(undefined);
return [x, y];
}
```
Try to keep the usage of tuple **local**. For data structures that are long-living and passed around often, prefer a **record**, which has named fields.
---
title: "Type"
description: "Types and type definitions in ReScript"
canonical: "/docs/manual/v11.0.0/type"
---
# Type
Types are the highlight of ReScript! They are:
- **Strong**. A type can't change into another type. In JavaScript, your variable's type might change when the code runs (aka at runtime). E.g. a `number` variable might change into a `string` sometimes. This is an anti-feature; it makes the code much harder to understand when reading or debugging.
- **Static**. ReScript types are erased after compilation and don't exist at runtime. Never worry about your types dragging down performance. You don't need type info during runtime; we report all the information (especially all the type errors) during compile time. Catch the bugs earlier!
- **Sound**. This is our biggest differentiator versus many other typed languages that compile to JavaScript. Our type system is guaranteed to **never** be wrong. Most type systems make a guess at the type of a value and show you a type in your editor that's sometime incorrect. We don't do that. We believe that a type system that is sometime incorrect can end up being dangerous due to expectation mismatches.
- **Fast**. Many developers underestimate how much of their project's build time goes into type checking. Our type checker is one of the fastest around.
- **Inferred**. You don't have to write down the types! ReScript can deduce them from their values. Yes, it might seem magical that we can deduce all of your program's types, without incorrectness, without your manual annotation, and do so quickly. Welcome to ReScript =).
The following sections explore more of our type system.
## Inference
This let-binding doesn't contain any written type:
```res example
let score = 10
let add = (a, b) => a + b
```
```js
var score = 10;
function add(a, b) {
return a + b | 0;
}
```
ReScript knows that `score` is an `int`, judging by the value `10`. This is called **inference**. Likewise, it also knows that the `add` function takes 2 `int`s and returns an `int`, judging from the `+` operator, which works on ints.
## Type Annotation
But you can also optionally write down the type, aka annotate your value:
```res example
let score: int = 10
```
```js
var score = 10;
```
If the type annotation for `score` doesn't correspond to our inferred type for it, we'll show you an error during compilation time. We **won't** silently assume your type annotation is correct, unlike many other languages.
You can also wrap any expression in parentheses and annotate it:
```res
let myInt = 5
let myInt: int = 5
let myInt = (5: int) + (4: int)
let add = (x: int, y: int) : int => x + y
let drawCircle = (~radius as r: int): circleType => /* code here */
```
```js
var myInt = 9;
function add(x, y) {
return x + y | 0;
}
function drawCircle(r) {
/* code here */
}
```
Note: in the last line, `(~radius as r: int)` is a labeled argument. More on this in the [function](function.md) page.
## Type Alias
You can refer to a type by a different name. They'll be equivalent:
```res example
type scoreType = int
let x: scoreType = 10
```
```js
var x = 10;
```
## Type Parameter (Aka Generic)
Types can accept parameters, akin to generics in other languages. The parameters' names **need** to start with `'`.
The use-case of a parameterized type is to kill duplications. Before:
```res example
// this is a tuple of 3 items, explained next
type intCoordinates = (int, int, int)
type floatCoordinates = (float, float, float)
let a: intCoordinates = (10, 20, 20)
let b: floatCoordinates = (10.5, 20.5, 20.5)
```
```js
var a = [10, 20, 20];
var b = [10.5, 20.5, 20.5];
```
After:
```res example
type coordinates<'a> = ('a, 'a, 'a)
let a: coordinates = (10, 20, 20)
let b: coordinates = (10.5, 20.5, 20.5)
```
```js
var a = [10, 20, 20];
var b = [10.5, 20.5, 20.5];
```
Note that the above codes are just contrived examples for illustration purposes. Since the types are inferred, you could have just written:
```res example
let buddy = (10, 20, 20)
```
```js
var buddy = [10, 20, 20];
```
The type system infers that it's a `(int, int, int)`. Nothing else needed to be written down.
Type arguments appear in many places. Our `array<'a>` type is such a type that requires a type parameter.
```res example
// inferred as `array`
let greetings = ["hello", "world", "how are you"]
```
```js
// inferred as `array`
var greetings = ["hello", "world", "how are you"];
```
If types didn't accept parameters, the standard library would need to define the types `arrayOfString`, `arrayOfInt`, `arrayOfTuplesOfInt`, etc. That'd be tedious.
Types can receive many arguments, and be composable.
```res example
type result<'a, 'b> =
| Ok('a)
| Error('b)
type myPayload = {data: string}
type myPayloadResults<'errorType> = array>
let payloadResults: myPayloadResults = [
Ok({data: "hi"}),
Ok({data: "bye"}),
Error("Something wrong happened!")
]
```
```js
var payloadResults = [
{
TAG: /* Ok */0,
_0: {data: "hi"}
},
{
TAG: /* Ok */0,
_0: {data: "bye"}
},
{
TAG: /* Error */1,
_0: "Something wrong happened!"
}
];
```
## Recursive Types
Just like a function, a type can reference itself within itself using `rec`:
```res example
type rec person = {
name: string,
friends: array
}
```
```js
// Empty output
```
## Mutually Recursive Types
Types can also be _mutually_ recursive through `and`:
```res example
type rec student = {taughtBy: teacher}
and teacher = {students: array}
```
```js
// Empty output
```
## Type Escape Hatch
ReScript's type system is robust and does not allow dangerous, unsafe stuff like implicit type casting, randomly guessing a value's type, etc. However, out of pragmatism, we expose a single escape hatch for you to "lie" to the type system:
```res
external myShadyConversion: myType1 => myType2 = "%identity"
```
```js
// Empty output
```
This declaration converts a `myType1` of your choice to `myType2` of your choice. You can use it like so:
```res example
external convertToFloat : int => float = "%identity"
let age = 10
let gpa = 2.1 +. convertToFloat(age)
```
```js
var age = 10;
var gpa = 2.1 + 10;
```
Obviously, do **not** abuse this feature. Use it tastefully when you're working with existing, overly dynamic JS code, for example.
More on externals [here](external.md).
**Note**: this particular `external` is the only one that isn't preceded by a `@` [attribute](attribute.md).
---
title: "TypeScript"
description: "GenType - Interoperability between ReScript and TypeScript"
canonical: "/docs/manual/v11.0.0/typescript-integration"
---
# ReScript & TypeScript
The ReScript compiler includes a code generation tool that lets you export ReScript values and types to use in TypeScript, and import TypeScript values and types into ReScript. It is called "genType".
The implementation of genType performs a type-directed transformation of ReScript programs after compilation. The transformed programs operate on data types idiomatic to TypeScript.
For example, a ReScript variant (which is represented as custom objects with tags at runtime):
```res
@genType
type t = | A(int) | B(string)
```
is exported to a TypeScript type:
```ts
type t = { TAG: "A"; _0: number } | { TAG: "B"; _0: string };
```
## A Quick Example
Let's assume we are working on a TypeScript codebase and we want to integrate a single ReScript function.
We want to be able to import the function like any other one in our existing TypeScript code, but we also want to preserve all the ReScript types in the TypeScript type system.
**That's exactly what genType was made for!**
First we'll set up a function:
```res
// src/Color.res
@genType
type color =
| Red
| Blue
@genType
let printColorMessage = (~color, ~message) => {
let prefix = switch color {
| Red => "\x1b[91m"
| Blue => "\x1b[94m"
}
let reset = "\x1b[0m"
Console.log(prefix ++ message ++ reset)
}
```
On a successful compile, `genType` will convert `src/Color.res` to a TypeScript file called `src/Color.gen.tsx` which will look something like this:
```ts
// src/Color.gen.tsx
/* TypeScript file generated from Color.res by genType. */
/* eslint-disable */
/* tslint:disable */
import * as ColorJS from "./Color.res.js";
export type color = "Red" | "Blue";
export const printColorMessage: (
color: color
) => void = ColorJS.printColorMessage as any;
```
genType automatically maps the `color` variant to TS via a string union type `"Red" | "Blue"`.
Within our TypeScript application, we can now import and use the function in the following manner:
```ts
// src/app.ts
import { printColorMessage } from "./Color.gen.tsx";
printColorMessage("Red", "Hello, genType!");
```
## Exporting an entire module
_Since ReScript `11.0.0`_ modules can be annotated with `@genType` as well. In that case, all types and values of the module will be converted to TS types. Example:
```res example
@genType
module Size = {
type t =
| Small
| Medium
| Large
let getNum = (size: t) =>
switch size {
| Small => 1.
| Medium => 5.
| Large => 10.
}
}
```
```ts
import * as MyCompBS__Es6Import from './MyComp.res';
const MyCompBS: any = MyCompBS__Es6Import;
export type Size_t = "Small" | "Medium" | "Large";
export const Size_getNum: (size:Size_t) => number = MyCompBS.Size.getNum;
export const Size: { getNum: (size:Size_t) => number } = MyCompBS.Size
```
## Setup
Add a `gentypeconfig` section to your `rescript.json` (See [Configuration](/docs/manual/latest/build-configuration#gentypeconfig) for details).
Every `genType` powered project requires a configuration item `"gentypeconfig"` at top level in the project's `rescript.json`.
The minimal configuration of genType is following:
```json
{
"gentypeconfig": {
"module": "esmodule",
"moduleResolution": "node",
"generatedFileExtension": ".gen.tsx"
}
}
```
And don't forget to make sure `allowJs` is set to `true` in the project's `tsconfig.json`:
```json
{
"compilerOptions": {
"allowJs": true
}
}
```
### TypeScript Module Resolutions
Make sure to set the same `moduleResolution` value in both `rescript.json` and `tsconfig.json`, so that the output of genType is done with the preferred module resolution.
For example if the TypeScript project uses JavaScript modules with `Node16` / `NodeNext` module resolution:
```json
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "node16"
}
}
```
Then `moduleResolution` in `gentypeconfig` should be same value:
```json
// rescript.json
{
"gentypeconfig": {
"moduleResolution": "node16"
}
}
```
In case of the TypeScript project using `Bundler` module resolution, `allowImportingTsExtensions` should also be `true`:
```json
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "bundler",
"allowImportingTsExtensions": true
}
}
```
```json
// rescript.json
{
"gentypeconfig": {
"moduleResolution": "bundler"
}
}
```
## Testing the Whole Setup
Open any relevant `*.res` file and add `@genType` annotations to any bindings / values / functions to be used from JavaScript. If an annotated value uses a type, the type must be annotated too. See e.g. [Hooks.res](https://github.com/rescript-lang/rescript/blob/master/tests/gentype_tests/typescript-react-example/src/Hooks.res).
Save the file and rebuild the project via `npm run res:build` or similar. You should now see a `*.gen.tsx` file with the same name (e.g. `MyComponent.res` -> `MyComponent.gen.tsx`).
Any values exported from `MyComponent.res` can then be imported from TypeScript. For example:
```js
import MyComponent from "./components/MyComponent.gen.tsx";
```
## Experimental features
These features are for experimentation only. They could be changed/removed any time, and not be considered breaking changes.
- Export object and record types as interfaces. To activate, add `"exportInterfaces": true` to the configuration. The types are also renamed from `name` to `Iname`.
## Shims
A shim is a TS file that provides user-provided definitions for library types.
Required only if one needs to export certain basic ReScript data types to JS when one cannot modify the sources to add annotations (e.g. exporting ReScript lists), and if the types are not first-classed in genType.
- Example: `Array` with format: `"RescriptModule=JavaScriptModule"`
Configure your shim files within `"gentypeconfig"` in your [`rescript.json`]:
```json
{
"gentypeconfig": {
"shims": {
"Js": "Js",
"ReactEvent": "ReactEvent",
"RescriptPervasives": "RescriptPervasives",
"ReasonReact": "ReactShim"
},
},
}
```
and add relevant `.shim.ts` files in a directory which is visible by ReScript e.g.
```
├── rescript.json
├── src
│ ├── shims
│ │ ├── Js.shim.ts
│ │ ├── ReactEvent.shim.ts
│ │ └── RescriptPervasives.shim.ts
```
Here are some examples:
```ts
// Excerpt from https://github.com/rescript-lang/rescript/blob/master/tests/gentype_tests/typescript-react-example/src/shims/Js.shim.ts
export type Json_t = unknown;
export type t = unknown;
```
```ts
// Excerpt from https://github.com/rescript-lang/rescript/tree/master/tests/gentype_tests/typescript-react-example/src/shims/JsxEvent.shim.ts
export type inputFocusEvent = React.FocusEvent;
```
More complete example shims can be found [here](https://github.com/rescript-lang/rescript/blob/master/tests/gentype_tests/typescript-react-example/src/shims/).
## Deprecated features
Features related to generating runtimes were deprecated since v11 and should no longer be used.
- **`@genType("alias")`** and **`@genType.as("alias")`**
- **`@genType.opaque`**
- **`@genType.import`**
- TypeScript Shims
genType does not generate anything runtime-related, and in the near future it generates definition files (`*.d.ts`) directly (See the [roadmap](https://github.com/rescript-lang/rescript/issues/6196)).
If any runtime code is required for interoperability with JavaScript / TypeScript projects, it can be written by hand, or request a relevant features (e.g. `@deriving`) to the compiler.
## Limitations
- **in-source = true**. Currently only supports ReScript projects with [in-source generation](/docs/manual/latest/build-configuration#package-specs) and file suffixes that end on `.js`, like `.res.js` or `.bs.js`.
- **Limited namespace support**. Currently there's limited [namespace](/docs/manual/latest/build-configuration#name-namespace) support, and only `namespace:true` is possible, not e.g. `namespace:"custom"`.
---
title: "Use Illegal Identifier Names"
description: "Handling (JS) naming collisions in ReScript"
canonical: "/docs/manual/v11.0.0/use-illegal-identifier-names"
---
# Use Illegal Identifier Names
Sometime, for e.g. a let binding or a record field, you might want to use:
- A capitalized name.
- A name that contains illegal characters (e.g. emojis, hyphen, space).
- A name that's one of ReScript's reserved keywords.
We provide an escape hatch syntax for these cases:
```res example
let \"my-🍎" = 10
type element = {
\"aria-label": string
}
let myElement = {
\"aria-label": "close"
}
let label = myElement.\"aria-label"
let calculate = (~\"Props") => {
\"Props" + 1
}
```
```js
var my$$unknown$unknown$unknown$unknown = 10;
var myElement = {
"aria-label": "close"
};
var label = myElement["aria-label"];
function calculate(Props) {
return Props + 1 | 0;
}
```
See the output. **Use them only when necessary**, for interop with JavaScript. This is a last-resort feature. If you abuse this, many of the compiler guarantees will go away.
---
title: "Variant"
description: "Variant data structures in ReScript"
canonical: "/docs/manual/v11.0.0/variant"
---
# Variant
So far, most of ReScript's data structures might look familiar to you. This section introduces an extremely important, and perhaps unfamiliar, data structure: variant.
Most data structures in most languages are about "this **and** that". A variant allows us to express "this **or** that".
```res example
type myResponse =
| Yes
| No
| PrettyMuch
let areYouCrushingIt = Yes
```
```js
var areYouCrushingIt = "Yes";
```
`myResponse` is a variant type with the cases `Yes`, `No` and `PrettyMuch`, which are called "variant constructors" (or "variant tag"). The `|` bar separates each constructor.
**Note**: a variant's constructors need to be capitalized.
## Variant Needs an Explicit Definition
If the variant you're using is in a different file, bring it into scope like you'd do [for a record](record.md#record-needs-an-explicit-definition):
```res example
// Zoo.res
type animal = Dog | Cat | Bird
```
```js
// Empty output
```
```res
// Example.res
let pet: Zoo.animal = Dog // preferred
// or
let pet2 = Zoo.Dog
```
```js
var pet = "Dog";
var pet2 = "Dog";
```
## Constructor Arguments
A variant's constructors can hold extra data separated by comma.
```res prelude
type account =
| None
| Instagram(string)
| Facebook(string, int)
```
```js
// Empty output
```
Here, `Instagram` holds a `string`, and `Facebook` holds a `string` and an `int`. Usage:
```res example
let myAccount = Facebook("Josh", 26)
let friendAccount = Instagram("Jenny")
```
```js
var myAccount = {
TAG: "Facebook",
_0: "Josh",
_1: 26
};
var friendAccount = {
TAG: "Instagram",
_0: "Jenny"
};
```
### Labeled Variant Payloads (Inline Record)
If a variant payload has multiple fields, you can use a record-like syntax to label them for better readability:
```res example
type user =
| Number(int)
| Id({name: string, password: string})
let me = Id({name: "Joe", password: "123"})
```
```js
var me = {
TAG: "Id",
name: "Joe",
password: "123"
};
```
This is technically called an "inline record", and only allowed within a variant constructor. You cannot inline a record type declaration anywhere else in ReScript.
Of course, you can just put a regular record type in a variant too:
```res example
type u = {name: string, password: string}
type user =
| Number(int)
| Id(u)
let me = Id({name: "Joe", password: "123"})
```
```js
var me = {
TAG: "Id",
_0: {
name: "Joe",
password: "123"
}
};
```
The output is slightly uglier and less performant than the former.
## Variant Type Spreads
Just like [with records](record#record-type-spread), it's possible to use type spreads to create new variants from other variants:
```rescript
type a = One | Two | Three
type b = | ...a | Four | Five
```
Type `b` is now:
```rescript
type b = One | Two | Three | Four | Five
```
Type spreads act as a 'copy-paste', meaning all constructors are copied as-is from `a` to `b`. Here are the rules for spreads to work:
- You can't overwrite constructors, so the same constructor name can exist in only one place as you spread. This is true even if the constructors are identical.
- All variants and constructors must share the same runtime configuration - `@unboxed`, `@tag`, `@as` and so on.
- You can't spread types in recursive definitions.
Note that you need a leading `|` if you want to use a spread in the first position of a variant definition.
### Pattern Matching On Variant
See the [Pattern Matching/Destructuring](pattern-matching-destructuring) section later.
## JavaScript Output
A variant value compiles to 3 possible JavaScript outputs depending on its type declaration:
- If the variant value is a constructor with no payload, it compiles to a string of the constructor name. Example: `Yes` compiles to `"Yes"`.
- If it's a constructor with a payload, it compiles to an object with the field `TAG` and the field `_0` for the first payload, `_1` for the second payload, etc. The value of `TAG` is the constructor name as string by default, but note that the name of the `TAG` field as well as the string value used for each constructor name [can be customized](#tagged-variants).
- Labeled variant payloads (the inline record trick earlier) compile to an object with the label names instead of `_0`, `_1`, etc. The object will have the `TAG` field as per the previous rule.
Check the output in these examples:
```res example
type greeting = Hello | Goodbye
let g1 = Hello
let g2 = Goodbye
type outcome = Good | Error(string)
let o1 = Good
let o2 = Error("oops!")
type family = Child | Mom(int, string) | Dad (int)
let f1 = Child
let f2 = Mom(30, "Jane")
let f3 = Dad(32)
type person = Teacher | Student({gpa: float})
let p1 = Teacher
let p2 = Student({gpa: 99.5})
type s = {score: float}
type adventurer = Warrior(s) | Wizard(string)
let a1 = Warrior({score: 10.5})
let a2 = Wizard("Joe")
```
```js
var g1 = "Hello";
var g2 = "Goodbye";
var o1 = "Good";
var o2 = {
TAG: "Error",
_0: "oops!"
};
var f1 = "Child";
var f2 = {
TAG: "Mom",
_0: 30,
_1: "Jane"
};
var f3 = {
TAG: "Dad",
_0: 32
};
var p1 = "Teacher";
var p2 = {
TAG: "Student",
gpa: 99.5
};
var a1 = {
TAG: "Warrior",
_0: {
score: 10.5
}
};
var a2 = {
TAG: "Wizard",
_0: "Joe"
};
```
## Tagged variants
- The `@tag` attribute lets you customize the discriminator (default: `TAG`).
- `@as` attributes control what each variant case is discriminated on (default: the variant case name as string).
### Example: Binding to TypeScript enums
```typescript
// direction.ts
/** Direction of the action. */
enum Direction {
/** The direction is up. */
Up = "UP",
/** The direction is down. */
Down = "DOWN",
/** The direction is left. */
Left = "LEFT",
/** The direction is right. */
Right = "RIGHT",
}
export const myDirection = Direction.Up;
```
You can bind to the above enums like so:
```rescript
/** Direction of the action. */
type direction =
| /** The direction is up. */
@as("UP")
Up
| /** The direction is down. */
@as("DOWN")
Down
| /** The direction is left. */
@as("LEFT")
Left
| /** The direction is right. */
@as("RIGHT")
Right
@module("./direction.js") external myDirection: direction = "myDirection"
```
Now, this maps 100% to the TypeScript code, including letting us bring over the documentation strings so we get a nice editor experience.
### String literals
The same logic is easily applied to string literals from TypeScript, only here the benefit is even larger, because string literals have the same limitations in TypeScript that polymorphic variants have in ReScript:
```typescript
// direction.ts
type direction = "UP" | "DOWN" | "LEFT" | "RIGHT";
```
There's no way to attach documentation strings to string literals in TypeScript, and you only get the actual value to interact with.
### Valid `@as` payloads
Here's a list of everything you can put in the `@as` tag of a variant constructor:
- A string literal: `@as("success")`
- An int: `@as(5)`
- A float: `@as(1.5)`
- True/false: `@as(true)` and `@as(false)`
- Null: `@as(null)`
- Undefined: `@as(undefined)`
## Untagged variants
With _untagged variants_ it is possible to mix types together that normally can't be mixed in the ReScript type system, as long as there's a way to discriminate them at runtime. For example, with untagged variants you can represent a heterogenous array:
```rescript
@unboxed type listItemValue = String(string) | Boolean(bool) | Number(float)
let myArray = [String("Hello"), Boolean(true), Boolean(false), Number(13.37)]
```
Here, each value will be _unboxed_ at runtime. That means that the variant payload will be all that's left, the variant case name wrapping the payload itself will be stripped out and the payload will be all that remains.
It, therefore, compiles to this JS:
```javascript
var myArray = ["hello", true, false, 13.37];
```
In the above example, reaching back into the values is as simple as pattern matching on them.
### Advanced: Unboxing rules
#### No overlap in constructors
A variant can be unboxed if no constructors have overlap in their runtime representation.
For example, you can't have `String1(string) | String2(string)` in the same unboxed variant, because there's no way for ReScript to know at runtime which of `String1` or `String2` that `string` belongs to, as it could belong to both.
The same goes for two records - even if they have fully different shapes, they're still JavaScript `object` at runtime.
Don't worry - the compiler will guide you and ensure there's no overlap.
#### What you can unbox
Here's a list of all possible things you can unbox:
- `string`: `String(string)`
- `float`: `Float(float)`. Note you can only have one of `float` or `int` because JavaScript only has `number` (not actually `int` and `float` like in ReScript) so we can't disambiguate between `float` and `int` at runtime.
- `int`: `Int(int)`. See note above on `float`.
- `bigint`: `BigInt(int)`. **Since 11.1** This is a distinct type from JavaScript's `number` type so you can use it beside either `float` or `int`.
- `bool`: `Boolean(bool)`
- `array<'value>`: `List(array)`
- `('a, 'b, 'c)`: `Tuple((string, int, bool))`. Any size of tuples works, but you can have only one case of array or tuple in a variant.
- `promise<'value>`: `Promise(promise)`
- `Dict.t`: `Object(Dict.t)`
- `Date.t`: `Date(Date.t)`. A JavaScript date.
- `Blob.t`: `Blob(Blob.t)`. A JavaScript blob.
- `File.t`: `File(File.t)`. A JavaScript file.
- `RegExp.t`: `RegExp(RegExp.t)`. A JavaScript regexp instance.
Again notice that the constructor names can be anything, what matters is what's in the payload.
> **Under the hood**: Untagged variants uses a combination of JavaScript `typeof` and `instanceof` checks to discern between unboxed constructors at runtime. This means that we could add more things to the list above detailing what can be unboxed, if there are useful enough use cases.
### Pattern matching on unboxed variants
Pattern matching works the same on unboxed variants as it does on regular variants. In fact, in the perspective of ReScript's type system there's no difference between untagged and tagged variants. You can do virtually the same things with both. That's the beauty of untagged variants - they're just variants to you as a developer.
Here's an example of pattern matching on an unboxed nullable value that illustrates the above:
```rescript
module Null = {
@unboxed type t<'a> = Present('a) | @as(null) Null
}
type userAge = {ageNum: Null.t}
type rec user = {
name: string,
age: Null.t,
bestFriend: Null.t,
}
let getBestFriendsAge = user =>
switch user.bestFriend {
| Present({age: Present({ageNum: Present(ageNum)})}) => Some(ageNum)
| _ => None
}
```
No difference to how you'd do with a regular variant. But, the runtime representation is different to a regular variant.
> Notice how `@as` allows us to say that an untagged variant case should map to a specific underlying _primitive_. `Present` has a type variable, so it can hold any type. And since it's an unboxed type, only the payloads `'a` or `null` will be kept at runtime. That's where the magic comes from.
### Decoding and encoding JSON idiomatically
With untagged variants, we have everything we need to define a native JSON type:
```rescript
@unboxed
type rec json =
| @as(null) Null
| Boolean(bool)
| String(string)
| Number(float)
| Object(Dict.t)
| Array(array)
let myValidJsonValue = Array([String("Hi"), Number(123.)])
```
Here's an example of how you could write your own JSON decoders easily using the above, leveraging pattern matching:
```rescript
@unboxed
type rec json =
| @as(null) Null
| Boolean(bool)
| String(string)
| Number(float)
| Object(Dict.t)
| Array(array)
type rec user = {
name: string,
age: int,
bestFriend: option,
}
let rec decodeUser = json =>
switch json {
| Object(userDict) =>
switch (
userDict->Dict.get("name"),
userDict->Dict.get("age"),
userDict->Dict.get("bestFriend"),
) {
| (Some(String(name)), Some(Number(age)), Some(maybeBestFriend)) =>
Some({
name,
age: age->Float.toInt,
bestFriend: maybeBestFriend->decodeUser,
})
| _ => None
}
| _ => None
}
let decodeUsers = json =>
switch json {
| Array(array) => array->Array.map(decodeUser)->Array.keepSome
| _ => []
}
```
Encoding that same structure back into JSON is also easy:
```rescript
let rec userToJson = user => Object(
Dict.fromArray([
("name", String(user.name)),
("age", Number(user.age->Int.toFloat)),
(
"bestFriend",
switch user.bestFriend {
| None => Null
| Some(friend) => userToJson(friend)
},
),
]),
)
let usersToJson = users => Array(users->Array.map(userToJson))
```
This can be extrapolated to many more cases.
### Advanced: Catch-all Constructors
With untagged variants comes a rather interesting capability - catch-all cases are now possible to encode directly into a variant.
Let's look at how it works. Imagine you're using a third party API that returns a list of available animals. You could of course model it as a regular `string`, but given that variants can be used as "typed strings", using a variant would give you much more benefit:
```rescript
type animal = Dog | Cat | Bird
type apiResponse = {
animal: animal
}
let greetAnimal = (animal: animal) =>
switch animal {
| Dog => "Wof"
| Cat => "Meow"
| Bird => "Kashiiin"
}
```
```javascript
```
This is all fine and good as long as the API returns `"Dog"`, `"Cat"` or `"Bird"` for `animal`.
However, what if the API changes before you have a chance to deploy new code, and can now return `"Turtle"` as well? Your code would break down because the variant `animal` doesn't cover `"Turtle"`.
So, we'll need to go back to `string`, loosing all of the goodies of using a variant, and then do manual conversion into the `animal` variant from `string`, right?
Well, this used to be the case before, but not anymore! We can leverage untagged variants to bake in handling of unknown values into the variant itself.
Let's update our type definition first:
```rescript
@unboxed
type animal = Dog | Cat | Bird | UnknownAnimal(string)
```
Notice we've added `@unboxed` and the constructor `UnknownAnimal(string)`. Remember how untagged variants work? You remove the constructors and just leave the payloads. This means that the variant above at runtime translates to this (made up) JavaScript type:
```
type animal = "Dog" | "Cat" | "Bird" | string
```
So, any string not mapping directly to one of the payloadless constructors will now map to the general `string` case.
As soon as we've added this, the compiler complains that we now need to handle this additional case in our pattern match as well. Let's fix that:
```rescript
@unboxed
type animal = Dog | Cat | Bird | UnknownAnimal(string)
type apiResponse = {
animal: animal
}
let greetAnimal = (animal: animal) =>
switch animal {
| Dog => "Wof"
| Cat => "Meow"
| Bird => "Kashiiin"
| UnknownAnimal(otherAnimal) =>
`I don't know how to greet animal ${otherAnimal}`
}
```
```javascript
function greetAnimal(animal) {
if (!(animal === "Cat" || animal === "Dog" || animal === "Bird")) {
return "I don't know how to greet animal " + animal;
}
switch (animal) {
case "Dog" :
return "Wof";
case "Cat" :
return "Meow";
case "Bird" :
return "Kashiiin";
}
}
```
There! Now the external API can change as much as it wants, we'll be forced to write all code that interfaces with `animal` in a safe way that handles all possible cases. All of this baked into the variant definition itself, so no need for labor intensive manual conversion.
This is useful in any scenario when you use something enum-style that's external and might change. Additionally, it's also useful when something external has a large number of possible values that are known, but where you only care about a subset of them. With a catch-all case you don't need to bind to all of them just because they can happen, you can safely just bind to the ones you care about and let the catch-all case handle the rest.
## Coercion
In certain situations, variants can be coerced to other variants, or to and from primitives. Coercion is always zero cost.
### Coercing Variants to Other Variants
You can coerce a variant to another variant if they're identical in runtime representation, and additionally if the variant you're coercing can be represented as the variant you're coercing to.
Here's an example using [variant type spreads](#variant-type-spreads):
```rescript
type a = One | Two | Three
type b = | ...a | Four | Five
let one: a = One
let four: b = Four
// This works because type `b` can always represent type `a` since all of type `a`'s constructors are spread into type `b`
let oneAsTypeB = (one :> b)
```
### Coercing Variants to Primitives
Variants that are guaranteed to always be represented by a single primitive at runtime can be coerced to that primitive.
It works with strings, the default runtime representation of payloadless constructors:
```rescript
// Constructors without payloads are represented as `string` by default
type a = One | Two | Three
let one: a = One
// All constructors are strings at runtime, so you can safely coerce it to a string
let oneAsString = (one :> string)
```
If you were to configure all of your construtors to be represented as `int` or `float`, you could coerce to those too:
```rescript
type asInt = | @as(1) One | @as(2) Two | @as(3) Three
let oneInt: asInt = One
let toInt = (oneInt :> int)
```
### Advanced: Coercing `string` to Variant
In certain situtations it's possible to coerce a `string` to a variant. This is an advanced technique that you're unlikely to need much, but when you do it's really useful.
You can coerce a `string` to a variant when:
- Your variant is `@unboxed`
- Your variant has a "catch-all" `string` case
Let's look at an example:
```rescript
@unboxed
type myEnum = One | Two | Other(string)
// Other("Other thing")
let asMyEnum = ("Other thing" :> myEnum)
// One
let asMyEnum = ("One" :> myEnum)
```
This works because the variant is unboxed **and** has a catch-all case. So, if you throw a string at this variant that's not representable by the payloadless constructors, like `"One"` or `"Two"`, it'll _always_ end up in `Other(string)`, since that case can represent any `string`.
## Tips & Tricks
**Be careful** not to confuse a constructor carrying 2 arguments with a constructor carrying a single tuple argument:
```res example
type account =
| Facebook(string, int) // 2 arguments
type account2 =
| Instagram((string, int)) // 1 argument - happens to be a 2-tuple
```
```js
// Empty output
```
### Variants Must Have Constructors
If you come from an untyped language, you might be tempted to try `type myType = int | string`. This isn't possible in ReScript; you'd have to give each branch a constructor: `type myType = Int(int) | String(string)`. The former looks nice, but causes lots of trouble down the line.
### Interop with JavaScript
_This section assumes knowledge about our JavaScript interop. Skip this if you haven't felt the itch to use variants for wrapping JS functions yet_.
Quite a few JS libraries use functions that can accept many types of arguments. In these cases, it's very tempting to model them as variants. For example, suppose there's a `myLibrary.draw` JS function that takes in either a `number` or a `string`. You might be tempted to bind it like so:
```res example
// reserved for internal usage
@module("myLibrary") external draw : 'a => unit = "draw"
type animal =
| MyFloat(float)
| MyString(string)
let betterDraw = (animal) =>
switch animal {
| MyFloat(f) => draw(f)
| MyString(s) => draw(s)
}
betterDraw(MyFloat(1.5))
```
```js
var MyLibrary = require("myLibrary");
function betterDraw(animal) {
MyLibrary.draw(animal._0);
}
betterDraw({
TAG: "MyFloat",
_0: 1.5
});
```
**Try not to do that**, as this generates extra noisy output. Instead, use the `@unboxed` attribute to guide ReScript to generate more efficient code:
```res example
// reserved for internal usage
@module("myLibrary") external draw : 'a => unit = "draw"
@unboxed
type animal =
| MyFloat(float)
| MyString(string)
let betterDraw = (animal) =>
switch animal {
| MyFloat(f) => draw(f)
| MyString(s) => draw(s)
}
betterDraw(MyFloat(1.5))
```
```js
var MyLibrary = require("myLibrary");
function betterDraw(animal) {
MyLibrary.draw(animal);
}
MyLibrary.draw(1.5);
```
Alternatively, define two `external`s that both compile to the same JS call:
```res example
@module("myLibrary") external drawFloat: float => unit = "draw"
@module("myLibrary") external drawString: string => unit = "draw"
```
```js
// Empty output
```
ReScript also provides [a few other ways](bind-to-js-function.md#modeling-polymorphic-function) to do this.
### Variant Types Are Found By Field Name
Please refer to this [record section](record#tips--tricks). Variants are the same: a function can't accept an arbitrary constructor shared by two different variants. Again, such feature exists; it's called a polymorphic variant. We'll talk about this in the future =).
## Design Decisions
Variants, in their many forms (polymorphic variant, open variant, GADT, etc.), are likely _the_ feature of a type system such as ReScript's. The aforementioned `option` variant, for example, obliterates the need for nullable types, a major source of bugs in other languages. Philosophically speaking, a problem is composed of many possible branches/conditions. Mishandling these conditions is the majority of what we call bugs. **A type system doesn't magically eliminate bugs; it points out the unhandled conditions and asks you to cover them**\*. The ability to model "this or that" correctly is crucial.
For example, some folks wonder how the type system can safely eliminate badly formatted JSON data from propagating into their program. They don't, not by themselves! But if the parser returns the `option` type `None | Some(actualData)`, then you'd have to handle the `None` case explicitly in later call sites. That's all there is.
Performance-wise, a variant can potentially tremendously speed up your program's logic. Here's a piece of JavaScript:
```js
let data = 'dog'
if (data === 'dog') {
...
} else if (data === 'cat') {
...
} else if (data === 'bird') {
...
}
```
There's a linear amount of branch checking here (`O(n)`). Compare this to using a ReScript variant:
```res example
type animal = Dog | Cat | Bird
let data = Dog
switch data {
| Dog => Console.log("Wof")
| Cat => Console.log("Meow")
| Bird => Console.log("Kashiiin")
}
```
```js
console.log("Wof");
var data = "Dog";
```
The compiler sees the variant, then
1. conceptually turns them into `type animal = "Dog" | "Cat" | "Bird"`
2. compiles `switch` to a constant-time jump table (`O(1)`).
---
title: "Warning Numbers"
description: "Available compiler warning numbers in ReScript"
canonical: "/docs/manual/v11.0.0/warning-numbers"
---
import { make as WarningTable } from "src/components/WarningTable.mjs";
# Warning Numbers
You can configure which warnings the ReScript compiler generates
[in the build configuration](/docs/manual/latest/build-configuration#warnings) or
using the [`@warning()`](/syntax-lookup#expression-warning-decorator) or the [`@@warning()`](/syntax-lookup#module-warning-decorator) decorator.