【问题标题】:How to use Js.Dict.t type for Js.Dict.get如何为 Js.Dict.get 使用 Js.Dict.t 类型
【发布时间】:2018-05-24 01:51:32
【问题描述】:

我正在尝试将一些 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 不喜欢它。

如何键入响应以使其正常工作?

谢谢!

【问题讨论】:

    标签: types reason bucklescript


    【解决方案1】:

    您可能想尝试以较小的增量构建它,因为您已经在这里给自己挖了一个很深的洞。

    首先,您是根据记录类型而不是 JS 对象类型来描述您的 JSON 响应。

    这是一个记录类型:

    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];
          ...
        }));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-09
      • 2022-01-05
      • 2012-09-29
      • 2020-09-13
      • 1970-01-01
      • 2019-01-16
      • 1970-01-01
      相关资源
      最近更新 更多