Docs / Language Manual / External

You are currently looking at the v8.0.0 docs (Reason v3.6 syntax edition). You can find the latest manual page here.

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.

Reason (Old Syntax)ML (Older Syntax)JS Output
 
[@bs.val] external setTimeout: (unit => unit, int) => float = "setTimeout";

There are several kinds of externals, differentiated and/or augmented through the @bs notation they carry. This page deals with the general, shared mechanism behind most externals. The different @bs annotations are documented in their respective pages later. A few notable ones:

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:

ReScriptJS OutputJS
 
// The type of document is just some random type 'a
// that we won't bother to specify
[@bs.val] external document: 'a = "document";

// call a method
document##addEventListener("mouseup", _event => {
  Js.log("clicked!");
});

// get a property
let loc = document##location;

// set a property
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

externals 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.

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.