将 JSON 字段转换为 ReasonML 变体

Convert JSON field to ReasonML variant

我有一个 JSON 结构,其中包含一个可以是对象或字符串的字段 period。 我已经在我的代码中准备好变体,并且工作正常:

type period = {
  start: string,
  end_: string,
};

type periodVariant =
  | String(string)
  | Period(period);

问题是当我尝试将输入 JSON 转换为变体类型时:我根本不知道该怎么做。 这是我的尝试:

let periodVariantDecode = (json: Js.Json.t): periodVariant => {
  switch(json) {
  | String(string) => String(Json.Decode.string(string))
  | period => Period(Json.Decode.{
      start: period |> field("start", string),
      end_: period |> field("end", string),
    })
  };
};

现在,这当然行不通了,因为我正在尝试将仍然属于 Js.Json.t 类型的内容与属于 periodVariantString 进行匹配,但是我不知道如何实现我想要的。

我看到你正在使用 bs-json 所以一种方法是利用 Json.Decode.optional returns None 如果解码失败。例如:

type period = {
  start: string,
  end_: string,
};

type periodVariant =
  | String(string)
  | Period(period);

let periodVariantDecode = json => {
  let periodString = json |> Json.Decode.(optional(string));
  switch (periodString) {
  | Some(periodString) => String(periodString)
  | None =>
    let periodObj =
      Json.Decode.{
        start: json |> field("start", string),
        end_: json |> field("end", string),
      };
    Period(periodObj);
  };
};

编译时 periodVariantDecode 应该是 Js.Json.t => periodVariant 类型。我不确定这是否是惯用的方式!

这就是 either is for. Along with map 方便地 "lift" 您的变体类型的现有解码器。

type period = {
  start: string,
  end_:  string,
};

type periodVariant =
  | String(string)
  | Period(period);

let period = json =>
  Json.Decode.{
    start: json |> field("start", string),
    end_:  json |> field("end", string),
  };

let periodVariantDecode =
  Json.Decode.(either(
    period |> map(p => Period(p)),
    string |> map(s => String(s))
  ));