Model callback with default parameter provided from JS files

I’m trying to refactor part of my JS/TS application into Rescript.
My goal is to rewrite part of the functionality with Rescript and then import rescript output into my javascript code.
I want to rewrite everything in one run, but realistically I’m able to do that step by step (the code base is just too big).
After I rewrote a few of my functions, I hit a wall when I imported them into Javascript.
I got Unhandled Rejection (TypeError): f.apply is not a function error from curry.js.
I tried to replicate that and I ended up with a different error, but I think it’s close.
Here is the repo
In Test.res I have:

@genType
let test = (
  ~v1: string,
  ~v2: int,
  ~parser: (~data: array<{..}>, ~vOne: Js.Undefined.t<string>=?, ~vTwo:Js.Undefined.t<int>=?) => {..},
) => {
  Js.log(parser);
  parser(
    ~data=[
      {
        "v1": v1,
        "v2": v2,
      },
    ],
    ~vOne=Some("world!")->Js.Undefined.fromOption,
    ~vTwo=Some(1)->Js.Undefined.fromOption,
  )
}

In App.js I defined “parser”:

const parser = (arr, plus_v1, plus_v2 = 2) => {
  const {v1, v2} = arr[0];
  console.log(`${v1} ${plus_v1}`, v2 + plus_v2);
}

and I’m trying to use it:

test("Hello", 1, parser);

It doesn’t work if I define a function with a default value. If it is:

(arr, plus_v1, plus_v2 ) => {

it works fine.

Theoretically, I could remove all default values from my legacy code, but in the longer run, I think it doesn’t worth it.
My question is, can I handle somehow callbacks that I will pass from js into Rescript output with default parameters?

I figured the solution. With “the dot” uncurried function based on that: Function | ReScript Language Manual (rescript-lang.org)

let test = (
  ~v1: string,
  ~v2: int,
  ~parser: (. ~data: array<{..}>, ~vOne: Js.Undefined.t<string>=?, ~vTwo:Js.Undefined.t<int>=?) => {..},
) => {
  Js.log(parser);
  parser(.
    ~data=[
      {
        "v1": v1,
        "v2": v2,
      },
    ],
    ~vOne=Some("world!")->Js.Undefined.fromOption,
    ~vTwo=Some(1)->Js.Undefined.fromOption,
  )
}

So simply adding . in definition and execution solved the problem.
I experienced different errors when a default value is present on the JS side, but all of them lead to a curry.js file.
Yesterday I was trying to add @uncurry on the definition, but it didn’t work (I guess it’s only for bindings). Today I found docs about uncurried functions in Rescript (shame it took me so long :sweat_smile: ), and I finally know what all these examples with “dot” on the forum mean :grinning_face_with_smiling_eyes:
Also, as a bonus I learned uncurried functions from JS are automatically curried when passed to Res output. Maybe it doesn’t work as expected with default parameters, but it still seems like a nice feature!

1 Like