4

在定义一个原因反应绑定时,我想知道如何确定一个接受多种类型的绑定。例如,我有一个应该接受的参数~valuestringnumber或。目前我正在使用,但我认为这不是最干净的方法,因为我更愿意明确定义类型。如何才能做到这一点?我看过但我不确定如何将外部语法组合到函数签名中。array(string)array(number)option('a)bs.unwrap

module Select = {
  [@bs.module "material-ui/Select"] external reactClass : ReasonReact.reactClass = "default";
  let make =
      (
        ...
        ~menuProps: option(Js.t({..}))=?,
        ~value: option('a), /* Should be type to string, number, Array of string and Array of number */
        ~style: option(ReactDOMRe.style)=?,
        ...
        children
      ) =>
    ReasonReact.wrapJsForReason(
      ~reactClass,
      ~props=
        Js.Nullable.(
          {
            ...
            "value": from_opt(value),
            "style": from_opt(style)            
          }
        ),
      children
    );
};

作为一个附带问题,由于未定义数字类型,我的绑定是否也必须将浮点数和整数映射为数字?

4

2 回答 2

4

这可以通过使用以下内容(受https://github.com/astrada/reason-react-toolbox/启发)来实现。

type jsUnsafe;

external toJsUnsafe : 'a => jsUnsafe = "%identity";

let unwrapValue =
    (r: [< | `Int(int) | `IntArray(array(int)) | `String(string) | `StringArray(array(string))]) =>
  switch r {
  | `String(s) => toJsUnsafe(s)
  | `Int(i) => toJsUnsafe(i)
  | `StringArray(a) => toJsUnsafe(a)
  | `IntArray(a) => toJsUnsafe(a)
  };

let optionMap = (fn, option) =>
  switch option {
  | Some(value) => Some(fn(value))
  | None => None
  };

module Select = {
  [@bs.module "material-ui/Select"] external reactClass : ReasonReact.reactClass = "default";
  let make =
      (
        ...
        ~menuProps: option(Js.t({..}))=?,
        ~value:
          option(
            [ | `Int(int) | `IntArray(array(int)) | `String(string) | `StringArray(array(string))]
           )=?,
        ~style: option(ReactDOMRe.style)=?,
        ...
        children
      ) =>
    ReasonReact.wrapJsForReason(
      ~reactClass,
      ~props=
        Js.Nullable.(
          {
            ...
            "value": from_opt(optionMap(unwrapValue, value)),
            "style": from_opt(style)            
          }
        ),
      children
    );
};

这可以通过以下方式使用;

<Select value=(`IntArray([|10, 20|])) />
<Select value=(`Int(10)) />

我从 reason-react-toolbox 复制toJsUnsafe,所以我不完全确定它到底做了什么,当我发现时我会更新我的答案。

unwrapValue函数采用一个可以是列出的类型之一的值并将其转换为 jsUnsafe。

的类型unwrapValue允许列出任何变体,但也允许其中的一个子集,例如。(这<是启用此功能的变体之前的版本)。

let option = (value: option([ | `String(string) | `Int(int)])) =>
  Js.Nullable.from_opt(option_map(unwrapValue, value));
于 2017-11-08T12:55:42.763 回答
3

只是为了添加到@InsidersByte 的答案,因为这个问题不是特定于原因的反应,并且可以概括:

module Value = {
  type t;
  external int : int => t = "%identity";
  external intArray : array(int) => t = "%identity";
  external string : string => t = "%identity";
  external stringArray : array(string) => t = "%identity";
};

let values : list(Value.t) = [
  Value.int(4),
  Value.stringArray([|"foo", "bar"|])
];

该解决方案在模块内部也是自包含的Value,并且与 JavaScript 等效方案相比不会产生任何开销,因为"%identity"外部是经过优化的无操作。

于 2017-11-08T13:25:32.093 回答