Lets say, that I have this function in Javascript which can generate string based on proper configuration:
function func(config) {
// ...
}
also, let's assume, that the config
variable has structure as below (all of these can be not given to function call):
{
"color": string, // can be: "blue", "red", "green"
"number": int, // can be: any number
"other": string, // can be: "x", "y"
}
How to create proper binding for this? I'm stuck with:
[@bs.deriving abstract]
type options = {
[@bs.optional]
color: [@bs.string] [ | `blue | `red | `green ]
[@bs.optional]
number: int,
[@bs.optional]
other: [@bs.string] [ | `x | `y ]
}
[@bs.module]
external func: options => string = "func";
But it does not work when trying to use like this:
let config = MyModule.config(
~color=`blue,
~number=123,
~other=`x
);
let value = MyModule.func(config);
The color
and other
values are integers, not strings.
This is a case of a JavaScript idiom for named parameters (objects with optional fields), needing to be adapted to the OCaml/ReasonML idiom (functions with actual labelled parameters). You would do this in three steps. Step 1, as Glenn showed, define an external for the config:
type config;
[@bs.obj] external config: (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit,
) => config = "";
Step 2, bind to the JavaScript function using the JavaScript style of the config object:
[@bs.val] external func: config => string = "";
Step 3, wrap the JavaScript function binding in an OCaml-idiomatic function with labelled parameters:
let func(~color=?, ~number=?, ~other=?, ()) = ()
|> config(~color?, ~number?, ~other?)
|> func;
You can use it like this:
let result = func(~color=`blue, ());