Bind to Global JS Values
First, make sure the value you'd like to model doesn't already exist in our provided API.
Some JS values, like setTimeout, live in the global scope. You can bind to them like so:
(We already provide setTimeout, clearTimeout and others in the Core API module).
This binds to the JavaScript setTimeout methods and the corresponding clearTimeout. The external's type annotation specifies that setTimeout:
Takes a function that accepts
unitand returnsunit(which on the JS side turns into a function that accepts nothing and returns nothing akaundefined),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.
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 externals 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:
you can bind to an arbitrarily deep object by passing a tuple to scope:
This binds to window.location.ancestorOrigins.length.
Special Global Values
Application globals like __DEV__ don't always exist. Referring to an undeclared identifier directly would trigger a JavaScript ReferenceError.
Bind optional properties of globalThis instead. Reading a missing property returns undefined, which ReScript represents as None:
This approach works for properties set on the global object. Module-scoped values, such as CommonJS's __filename, and identifiers replaced by a bundler are not necessarily properties of globalThis.
Another example: