javascript - 将记录列表导出到不带标签的 JavaScript 对象数组

标签 javascript ffi reason bucklescript

假设我有以下 ReasonML 类型:

type xEntry = {title: string};
type yEntry = {value: int};
type entry =
  | X(xEntry)
  | Y(yEntry);

我想将以下值导出到 JavaScript 端:

/* Input */
let value = [
  X({title: "foo"}),
  Y({value: 123})
];

结构如下:

/* Expected output */
[{"type": "X", "title": "foo"},
 {"type": "Y", "value": 123}]

我几乎可以用下面的代码实现它:

[@bs.deriving abstract]
type jsXEntry = {
  [@bs.as "type"]
  type_: string,
  title: string,
};

[@bs.deriving abstract]
type jsYEntry = {
  [@bs.as "type"]
  type_: string,
  value: int,
};

type jsEntry =
  | JsX(jsXEntry)
  | JsY(jsYEntry);

let fromEntry = entry =>
  switch (entry) {
  | X(v) => JsX(jsXEntry(~type_="X", ~title=v.title))
  | Y(v) => JsY(jsYEntry(~type_="Y", ~value=v.value))
  };

let convertToJs = (entries: list(entry)): Js.Array.t(jsEntry) =>
  Array.map(fromEntry, ArrayLabels.of_list(entries));

不幸的是(但可以理解)我得到以下结果:

/* convertToJs(value) */
[ [ { type: 'X', title: 'foo' }, tag: 0 ],
  [ { type: 'Y', value: 123 }, tag: 1 ] ]

此结果包含标记记录(单元素数组,具有 tag 属性),这不是我要找的。

我可以在 JavaScript 端编写一个转换函数来摆脱它,但我更愿意直接从 ReasonML 生成正确的结构。

此外,我想避免使用 %bs.raw尽可能构建。

如何生成顶部显示的预期输出?

最佳答案

您可以使用抽象类型而不是 jsEntry 的变体,然后使用 Obj.magic 绕过类型系统并将其转换为该类型:

type jsEntry;

let fromEntry: entry => jsEntry = 
  fun | X(v) => Obj.magic(jsXEntry(~type_="X", ~title=v.title))
      | Y(v) => Obj.magic(jsYEntry(~type_="Y", ~value=v.value))
;

但是要小心 Obj.magic,因为绕过类型系统很容易破坏您的代码。确保始终对类型进行注释,以免类型推断给您带来意外。

关于javascript - 将记录列表导出到不带标签的 JavaScript 对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51800688/

相关文章:

node.js - 获取 Node.js 中生成子进程的结果

javascript - onkeydown 在 Greasemonkey 中不起作用

javascript - 现代版本 EXT JS 6.2.0 中的 loadRecord() 方法

rust - 如何创建 FFI 绑定(bind)到需要 OR 字节的 C 函数?

ocaml - OCaml 或 Reason 的调用图生成器

ocaml - 如何请求变量的类型类?

javascript - React js - 使用数组值和换行符更新状态

javascript - Protractor - 如何在配置文件中排除 spec 文件?

opencv - 使用 Racket FFI 快速访问数组

pointers - 从 Rust FFI 中检索一个 float 指针