I'm trying to render a component with reason-react after I get data from fetch but I receive a type error. This is my code:
GetData.re:
let get = () => Js.Promise.(
Fetch.fetch("localhost:8000/data.json")
|> then_(Fetch.Response.json)
|> resolve
);
Main.re:
let data = () =>
GetData.get()
|> Js.Promise.then_(result =>
Js.Promise.resolve(
ReactDOMRe.renderToElementWithId(
<ItemsList itemsList=result />,
"root"
)
)
)
And I recive this error:
29 │ let data = () =>
30 │ GetData.get()
31 │ |> Js.Promise.then_(result =>
32 │ Js.Promise.resolve(
. │ ...
37 │ )
38 │ );
This has type:
(Js.Promise.t(list(Item.item))) => Js.Promise.t(unit)
But somewhere wanted:
(Js.Promise.t(Js.Promise.t(Js.Json.t))) => 'a
The incompatible parts:
Js.Promise.t(list(Item.item)) (defined as Js.Promise.t(list(Item.item)))
vs
Js.Promise.t(Js.Promise.t(Js.Json.t)) (defined as
Js.Promise.t(Js.Promise.t(Js.Json.t)))
Further expanded:
list(Item.item)
vs
Js.Promise.t(Js.Json.t) (defined as Js.Promise.t(Js.Json.t))
ninja: build stopped: subcommand failed.
I also try to replace render with simple Js.log(result)
and it works, I try to check type of Js.log
and render
(passing their invocation to a function which takes an int
and watching the error) and they are both unit
Where is my mistake? and is there something like toplevel/utop for Reason? It actually helps a lot in OCaml
You have several issues in your code:
Fetch.Response.json
returns a Js.Json.t
(wrapped in a promise), indicating the structure of the data is unknown to the type system and needs to be decoded. You can do that using bs-json for example.
Js.Promise.resolve
takes any value and wraps that value in a Js.Promise.t
. But since Js.Promise.then_
already returns a promise, you now have a promise wrapped in a promise. You should therefore just remove |> resolve
from your get
function.
The type error tells you about both of these issues (list(Item.item) vs Js.Promise.t(Js.Json.t) (defined as Js.Promise.t(Js.Json.t))
), but it doesn't tell you where it "went wrong". To narrow down type errors like this you can annotate the type of you functions and let-bindings. For example, if you had annotated get
:
let get : Js.Promise.t(list(Item.item))) = ...
It would have shown you that the problem is within the get
function.
Rule of thumb: Don't assume, annotate.
Edit: To answer the toplevel/repl question: There is a toplevel for Reason called rtop
, but it does not work with BuckleScript and JavaScript APIs. There is also the Reason playground which does work with BuckleScript and JS APIs, but is not able to load external libraries.