Как использовать тип Js.Dict.t для Js.Dict.get - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь преобразовать JS в Reason, и мне нужно набрать ответ JSON, а также проверить, существует ли ключ в объекте.

Это мой текущий код:

let api_key = "";
let api_url = "http://ws.audioscrobbler.com/2.0";
let method = "user.getRecentTracks";
let user = "montogeek";

type trackAttr = {
  nowplaying: bool
};

type artistT = {
  text: string
}

type trackT = {
  attr: trackAttr,
  name: string,
  artist: artistT
};

type recentTrackT = {
  track: array(Js.Dict.t(trackT))
};

type response = {
  recenttracks: recentTrackT
};

Js.Promise.(Fetch.fetch(api_url ++ "?method=" ++ method ++ "&" ++ user ++ "=" ++ user ++ "&limit=1&format=json&api_key=" ++ api_key)
    |> then_(Fetch.Response.json)
    |> then_(json: response => {
      let lasttrack = json.recenttracks.track[0];

      let online = switch (Js.Dict.get(lasttrack, "attr")) {
      | None => false
      | Some(track) => track.attr.nowplaying
      };
      let info = online ? "Enjoying" ++ lasttrack.name ++ "by " ++ lasttrack.artist["#text"] ++ "}" : "";

      { online, info }
    }));

В настоящее время я получаю эту ошибку:

We've found a bug for you!
  /Users/montogeek/Infinite/Lov/online/src/lastfm.re 37:41-49

  35 ┆ | Some(track) => track.attr.nowplaying
  36 ┆ };
  37 ┆ let info = online ? "Enjoying" ++ lasttrack.name ++ "by " ++ lasttrack
       .artist["#text"] ++ "}" : "";
  38 ┆
  39 ┆ { online, info }

  This has type:
    Js.Dict.t(trackT) (defined as Js.Dict.t(trackT))
  But somewhere wanted:
    trackT

Я не могу удалить Js.Dict.t тип, потому что Js.Dict.get не понравится.

Как я могу печататьответ так работает?

Спасибо!

1 Ответ

0 голосов
/ 23 мая 2018

Возможно, вы захотите попытаться построить это с меньшими приращениями, поскольку вы копали себе здесь довольно глубокую дыру.

Прежде всего, вы описываете свой JSON-ответ с точки зрения типов записей,не типы объектов JS.

Это тип записи:

type  t = { foo: string };

, а это тип объекта JS:

type t = {. "foo": string };

Небольшая, но довольно существенная разница.

Во-вторых, Js.Dict.t(trackT) - это не то, что вы думаете (хотя, что именно, это также неясно для меня).Он описывает объект JS, используемый в качестве хэша, с ключами типа String и значениями типа trackT.Это похоже на попытку исправить первую проблему, но служит только для того, чтобы сделать дыру глубже, поэтому, возможно, просто отмените это.

В-третьих, вы не можете просто утверждать, что ответ JSON имеет тип responseаннотируя это.Это система типов звука, где вы получите ошибку типа.Если вы хотите обойти систему типов (что почти всегда является плохой идеей), вы должны быть более откровенны в этом.

Существует также ряд других незначительных ошибок, но это выходит за рамки этого.

Так что вместо этого вы должны сделать одну из двух вещей:

Правильный способ - использовать такую ​​библиотеку, как bs-json длядекодируйте ответ JSON в типы записей, которые вы уже определили, проверяя форму данных на границе, где это должно быть сделано, и затем продолжайте использовать типы записей как обычно:

/* assume record types are defined above */

module Decode = {
  open Json.Decode;

  let trackAttr = json => {
    nowplaying: json |> field("nowplaying", bool)
  };

  let artist = json => {
    text: json |> field("text", string)
  }

  let track = json => {
    attr: json |> optional(field("attr", trackAttr)),
    name: json |> field("name", string),
    artist: json |> field("artist", artist)
  };

  let recentTrack = json => {
    track: json |> field("track", array(track))
  };

  let response = json => {
    recenttracks: json |> field("recenttracks", recentTrack)
  };
};

Js.Promise.(Fetch.fetch(api_url ++ "?method=" ++ method ++ "&" ++ user ++ "=" ++ user ++ "&limit=1&format=json&api_key=" ++ api_key)
    |> then_(Fetch.Response.json)
    |> then_(json => {
      let response = Decode.response(json);
      let lasttrack = response.recenttracks.track[0];
      ...
    }));

Быстрый и грязный способ - преобразовать типы записей в типы объектов JS, а затем просто утверждать, что данные имеют эту форму, тем самым обходя систему типов.Если он не имеет ожидаемой формы, вы можете получить ошибки во время выполнения в любом месте, и вам нужно будет отследить источник проблемы вручную.Вот как это может выглядеть:

type trackAttr = {.
  "nowplaying": bool
};

type artistT = {.
  "text": string
}

type trackT = {.
  "attr": trackAttr,
  "name": string,
  "artist": artistT
};

type recentTrackT = {.
  "track": array(trackT)
};

type response = {.
  "recenttracks": recentTrackT
};

external unsafeCastJsonAsResponse : Js.Json.t => response = "%identity";

Js.Promise.(Fetch.fetch(api_url ++ "?method=" ++ method ++ "&" ++ user ++ "=" ++ user ++ "&limit=1&format=json&api_key=" ++ api_key)
    |> then_(Fetch.Response.json)
    |> then_(json => {
      let response = unsafeCastJsonAsResponse(json);
      let lasttrack = response##recenttracks##track[0];
      ...
    }));
...