假设我有以下 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
属性),这不是我要找的。p>
我可以在 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/