Interop Cheatsheet
The next few sections will cover these in detail. Feel free to skip this one if nothing makes sense yet!
Raw JS
RElet add = [%raw "a + b"];
[%%raw "var a = 1"];
String Unicode & Interpolation
REJs.log({js|你好,
世界|js});
let world = "world";
let helloWorld = {j|hello, $world|j};
Global Value
RE[@bs.val] external setTimeout : (unit => unit, int) => float = "setTimeout";
Global Module
RE[@bs.val] [@bs.scope "Math"] external random : unit => float = "random";
let someNumber = random();
[@bs.val] [@bs.scope ("window", "location", "ancestorOrigins")] external length : int = "length";
Nullable
RElet a = Some(5); /* compiles to 5 */
let b = None; /* compiles to undefined */
Handling a value that can be undefined
and null
, by ditching the option
type and using Js.Nullable.t
:
RElet jsNull = Js.Nullable.null;
let jsUndefined = Js.Nullable.undefined;
let result1: Js.Nullable.t(string) = Js.Nullable.return("hello");
let result2: Js.Nullable.t(int) = Js.Nullable.fromOption(Some(10));
let result3: option(int) = Js.Nullable.toOption(Js.Nullable.return(10));
Object
Records as Objects
Since BuckleScript 7 (preferred for JS object interop)
REtype action = {
[@bs.as "type"] type_: string,
username: string
};
[@bs.module "actions/addUser.js"] external createAddUser: string => action = "addUser";
let myAction = createAddUser("reason");
Hash Map Mode
RElet myMap = Js.Dict.empty();
Js.Dict.set(myMap, "Allison", 10);
Abstract Record Mode
RE[@bs.deriving abstract]
type person = {
[@bs.optional] name: string,
age: int,
mutable job: string,
};
[@bs.send] external getNickname : person => string = "getNickname";
[@bs.val] external john : person = "john";
let age = john->ageGet;
john->jobSet("Accountant");
let nick = john->getNickname;
New Instance
REtype t;
[@bs.new] external createDate : unit => t = "Date";
Function
Object Method & Chaining
RE[@bs.send] external map : (array('a), 'a => 'b) => array('b) = "map";
[@bs.send] external filter : (array('a), 'a => 'b) => array('b) = "filter";
/* 2, 4 */
[|1, 2, 3|]
->map(a => a + 1)
->filter(a => a mod 2 == 0)
->Js.log;
Variadic (was bs.splice prior to version 4.08)
RE[@bs.module "path"] [@bs.variadic]
external join : array(string) => string = "join";
Polymorphic Function
RE[@bs.module "Drawing"] external drawCat : unit => unit = "draw";
[@bs.module "Drawing"] external drawDog : (~giveName: string) => unit = "draw";
RE[@bs.val] external padLeft : (
string,
[@bs.unwrap] [
| `Str(string)
| `Int(int)
]
) => string = "padLeft";
padLeft("Hello World", `Int(4));
Curry/Uncurry
RElet add = [@bs] ((x, y, z) => x + y + z);
let six = [@bs] add(1, 2, 3);
Module
RE[@bs.module "path"] external dirname : string => string = "dirname";
Import module.exports
RE[@bs.module] external simpleFunction : string => string = "simple-module-that-is-a-function";
Import Default
It's important to note that you are not providing the module path to bs.module
, but instead as the last argument of external
.
RE[@bs.module] external leftPad : (string, int) => string = "./leftPad";
Import ES6 default compiled from Babel:
RE[@bs.module "./student"] external studentName : string = "default";
Export ES6 default
RElet default = "Bob";
Identity External
Final escape hatch converter. Do not abuse.
REexternal myShadyConversion : foo => bar = "%identity";
You can find more examples for the various bs.*
attributes here.