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

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.

ReScriptJS Output
@val external setTimeout: (unit => unit, int) => float = "setTimeout"

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

  • @val, @scope: bind to global JS values.

  • @module: bind to JS imported/exported values.

  • @send: bind to JS methods.

You can also use our Syntax Lookup tool to find them.

Related: see also our list of external 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:

ReScriptJS Output
// 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"

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.

Note: do also use externals 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.

Shared Data TypesBind to JS Object

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on