假设我在Javascript中有这个函数,它可以根据适当的配置生成字符串:
function func(config) {
// ...
}
另外,让我们假设config
变量具有如下结构(所有这些都可以不提供给函数调用):
{
"color": string, // can be: "blue", "red", "green"
"number": int, // can be: any number
"other": string, // can be: "x", "y"
}
如何为此创建正确的绑定?我被困住了:
[@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";
但是,当尝试像这样使用时,它不起作用:
let config = MyModule.config(
~color=`blue,
~number=123,
~other=`x
);
let value = MyModule.func(config);
color
和other
值是整数,而不是字符串。
发布于 2019-03-26 02:00:48
这是一个用于命名参数(具有可选字段的对象)的JavaScript习惯用法,需要适应OCaml/ReasonML习惯用法(具有实际标记的参数的函数)。您将通过三个步骤来完成此操作。如Glenn所示,第1步为配置定义外部:
type config;
[@bs.obj] external config: (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit,
) => config = "";
步骤2,使用配置对象的JavaScript样式绑定到JavaScript函数:
[@bs.val] external func: config => string = "";
步骤3,使用带标签的参数将JavaScript函数绑定包装在一个OCaml惯用函数中:
let func(~color=?, ~number=?, ~other=?, ()) = ()
|> config(~color?, ~number?, ~other?)
|> func;
你可以这样使用它:
let result = func(~color=`blue, ());
发布于 2019-03-26 00:20:26
@bs
属性通常是未经深思熟虑的技巧,您不应该期望它能很好地与其他属性一起工作,或者真正地与文档所解释或显示的示例之外的任何东西一起工作。然而,如果一个属性被用在了不想使用的地方,你通常至少会得到一个关于该属性未被使用的警告,你的代码就是这么做的。
特别是@bs.string
只适用于外部变量最外层的类型,即其值将被直接传递给外部函数的类型。还有一种使用外部函数创建JavaScript对象的方法,这种方法使用的魔力更少,让您可以更好地控制API。据我所知,与@bs.deriving
相比,唯一的缺点是不能使用像@bs.as
这样的东西覆盖字段名。它们必须是有效的OCaml标识符。
下面是使用带有@bs.obj
注释的外部函数实现的示例
type options;
[@bs.obj] external options : (
~color:[@bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[@bs.string] [`x | `y]=?,
unit
) => options = "";
要使用它,您可以使用与@bs.deriving
完全相同的名称
let config = options(~color=`blue,~number=123, ~other=`x, ());
但即使这样,我也遇到了一些边缘情况,传入的是整数值,而不是字符串。出于这个原因,我倾向于完全避免使用多态变体属性,而是使用普通变体以及转换函数。这还有一个额外的好处,那就是更加地道,更好地融入其中,并且与非BuckleScript代码更具互操作性。
下面是使用这种方法的示例:
type color = Blue | Red | Green;
let colorToString = fun
| Blue => "blue"
| Red => "red"
| Green => "green";
type other = X | Y;
let otherToString = fun
| X => "x"
| Y => "y";
[@bs.obj] external options : (
~color:string=?,
~number:int=?,
~other:string=?,
unit
) => options = "";
[@bs.module] external func: options => string = "func";
let func = (~color=?, ~number=?, ~other=?, ()) =>
func(options(
~color = ?Belt.Option.map(color, colorToString),
~number?,
~other = ?Belt.Option.map(other, otherToString),
()));
let config = func(~color=Blue,~number=123, ~other=X, ());
https://stackoverflow.com/questions/55325408
复制相似问题