Skip to content

Latest commit

 

History

History
197 lines (137 loc) · 4.14 KB

bind-to-js-object.mdx

File metadata and controls

197 lines (137 loc) · 4.14 KB
titledescriptioncanonical
Bind to JS Object
Interop with JS objects in ReScript
/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 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!

<CodeTab labels={["ReScript", "JS Output"]}>

typeperson= { name: string, friends: array<string>, age: int, } @module("MySchool") externaljohn: person="john"letjohnName=john.name
varMySchool=require("MySchool");varjohnName=MySchool.john.name;

External is documented here. @module is documented here.

If you want or need to use different field names on the ReScript and the JavaScript side, you can use the @as decorator:

<CodeTab labels={["ReScript", "JS Output"]}>

typeaction= { @as("type") type_: string } letaction= {type_: "ADD_USER"}
varaction={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:

<CodeTab labels={["ReScript", "JS Output"]}>

typet= { @as("0") foo: int, @as("1") bar: string, } letvalue= {foo: 7, bar: "baz"}
varvalue=[7,"baz"];

Bind Using ReScript Object

Alternatively, you can use ReScript object to model a JS object too:

<CodeTab labels={["ReScript", "JS Output"]}>

typeperson= { "name": string, "friends": array<string>, "age": int, } @module("MySchool") externaljohn: person="john"letjohnName=john["name"]
varMySchool=require("MySchool");varjohnName=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:

<CodeTab labels={["ReScript", "JS Output"]}>

typetextarea @setexternalsetName: (textarea, string) =>unit="name" @getexternalgetName: textarea=>string="name"

You can also use get_index and set_index to access a dynamic property or an index:

<CodeTab labels={["ReScript", "JS Output"]}>

typet @newexternalcreate: int=>t="Int32Array" @get_indexexternalget: (t, int) =>int="" @set_indexexternalset: (t, int, int) =>unit=""leti32arr=create(3) i32arr->set(0, 42) Console.log(i32arr->get(0))
vari32arr=newInt32Array(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, 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():

<CodeTab labels={["ReScript", "JS Output"]}>

typet @newexternalcreateDate: unit=>t="Date"letdate=createDate()
vardate=newDate();

You can chain new and module if the JS module you're importing is itself a class:

<CodeTab labels={["ReScript", "JS Output"]}>

typet @new @moduleexternalbook: unit=>t="Book"letmyBook=book()
varBook=require("Book");varmyBook=newBook();
close