Fer*_*oya 3 types reason bucklescript
我试图将一些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 }
}));
Run Code Online (Sandbox Code Playgroud)
目前我收到此错误:
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
Run Code Online (Sandbox Code Playgroud)
我不能删除Js.Dict.t类型因为Js.Dict.get不喜欢它.
如何输入响应以使其有效?
谢谢!
你可能想尝试以较小的增量来构建它,因为你在这里挖了一个很深的洞.
首先,您要根据记录类型而不是JS对象类型来描述您的JSON repsonse.
这是一种记录类型:
type t = { foo: string };
Run Code Online (Sandbox Code Playgroud)
这是一个JS对象类型:
type t = {. "foo": string };
Run Code Online (Sandbox Code Playgroud)
一个微妙但非常显着的差异.
其次Js.Dict.t(trackT)不是你的想法(虽然这对我来说也不清楚).它描述了一个用作哈希的JS对象,其类型String和值类型的键trackT.这看起来像是试图解决第一个问题,但只是为了使洞更深,所以也许只是恢复它.
第三,您不能通过response注释来断言JSON响应具有类型.这是一个声音类型系统,这只会给你一个类型错误.如果你想绕过类型系统(这几乎总是一个坏主意),你必须更加明确它.
还有一些其他小错误,但这超出了范围.
那么你应该做的是两件事之一:
正确的方法是使用诸如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];
...
}));
Run Code Online (Sandbox Code Playgroud)
快速而肮脏的方法是将记录类型转换为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];
...
}));
Run Code Online (Sandbox Code Playgroud)