Handling optional arguments and pruning them from the JS object

We can use [@bs.obj] to create a javascript object, and it correctly handles optional arguments. For example:

[@bs.obj]
  external makeProps :
    (
      ~a: int,
      ~b: string=?,
      unit
    ) =>
    _ =
    "";

Js.log(makeProps(~a=10, ~b="Hi there", ()));
Js.log(makeProps(~a=10, ()));

Correctly prints out

{"a":10,"b":"Hi there"}
{"a":10}

However, if we want to type, or manipulate one of the parameters before calling makeProps then we lose the "optionalness" of the parameter:

type aType =
  | One
  | Two;

[@bs.obj] external makeProps : (~a: int, ~b: string=?, unit) => _ = "";

let theFn = (~a: int, ~b=?, ()) => {
  let bStr =
    switch b {
    | None => ""
    | Some(x) =>
      switch x {
      | One => "one"
      | Two => "two"
      }
    };
  let o = makeProps(~a, ~b=bStr, ());
  o;
};
Js.log(theFn(~a=10, ~b=One, ()));
Js.log(theFn(~a=10, ()));

which prints:

{"a":10,"b":"one"}
{"a":10,"b":""}

Solution

We need to use a syntax "trick" to allow us to pass the option again (from https://reasonml.github.io/docs/en/function.html#explicitly-passed-optional). Specially, rather than converting the optional variant to a string, convert it to an optional string:

type aType =
  | One
  | Two;

[@bs.obj] external makeProps : (~a: int, ~b: string=?, unit) => _ = "";

let theFn = (~a: int, ~b=?, ()) => {
  let bStr =
    switch b {
    | None => None
    | Some(x) =>
      switch x {
      | One => Some("one")
      | Two => Some("two")
      }
    };
  let o = makeProps(~a, ~b=?bStr, ());
  o;
};

Js.log(theFn(~a=10, ~b=One, ()));
Js.log(theFn(~a=10, ()));

which now returns:

{"a":10,"b":"one"}
{"a":10}

Refinement

Thanks to the excellent help from the https://discordapp.com/invite/reasonml we can reduce this further to:

type aType =
  | One
  | Two;

[@bs.obj] external makeProps : (~a: int, ~b: string=?, unit) => _ = "";

let theFn = (~a: int, ~b=?, ()) => {
  let b =
    Js.Option.map(
      [@bs]
      (
        (x) =>
          switch x {
          | One => "one"
          | Two => "two"
          }
      ),
      b
    );
  let o = makeProps(~a, ~b?, ());
  o
};

Js.log(theFn(~a=10, ~b=One, ()));

Js.log(theFn(~a=10, ()));

results matching ""

    No results matching ""