Search code examples
ffireasonbucklescript

How do I use the [@bs.this] BuckleScript attribute in Reason (ReasonML)?


I'm trying to write ReasonML that compiles to this JS:

function main(example) {
    example.foo = function() {
        console.log(this)
    }
}

Here's my Reason:

let module Example = {
    type t;
    external set_foo_method : t => (t => unit [@bs.this]) => unit = "foo" [@@bs.set];
};

let main = fun example => Example.set_foo_method example (fun [@bs.this] x => {
    Js.log(x);
});

I'm getting a syntax error on the line and column for the second [@bs.this].

File "/Users/maxwellheiber/dev/rerect/src/demo.re", line 6, characters 62-64:
Error: 742: <SYNTAX ERROR>

I'm following the BuckleScript docs for @bs.this.

Is the syntax for using BuckleScript to bind to this different in Reason as compared to OCaml? The following OCaml (not Reason) with BuckleScript attributes compiles without errors to the correct JS:

module Example = struct
    type t
    external set_foo_method : t -> (t -> unit [@bs.this]) -> unit = "foo" [@@bs.set]
end

let main example = Example.set_foo_method example (fun [@bs.this] x -> Js.log(x))

How do I use the [@bs.this] BuckleScript attribute in Reason to generate JS that uses this?


Solution

  • Yes, attribute precedence and such is unfortunately subtly different. Reason Tools (which is great for converting small snippets like this) says this is what you want:

    module Example = {
      type t;
      external set_foo_method : t => (t => unit) [@bs.this] => unit = "foo" [@@bs.set];
    };
    
    let main example => Example.set_foo_method example ((fun x => Js.log x) [@bs.this]);
    

    It will compile to

    function main(example) {
      example.foo = (function () {
          var x = this ;
          console.log(x);
          return /* () */0;
        });
      return /* () */0;
    }