3

我有一个 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),
    })
  };
};

现在,这当然行不通,因为我正在尝试匹配仍然属于 my 一部分的类型的东西Js.Json.tStringperiodVariant我不知道如何实现我想要的。

4

2 回答 2

6

这是either为了什么。以及map方便地将现有解码器“提升”到您的变体类型。

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))
  ));
于 2018-06-19T11:37:51.460 回答
2

我看到您正在使用 bs-json,因此一种方法是利用解码失败Json.Decode.optional时返回的事实。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为 type Js.Json.t => periodVariant。我不确定这是否是惯用的方式!

于 2018-06-19T06:16:23.853 回答