Ah, I figured it out!
I moved the binding to json into MakeLoader and then change up how I pass the data to json.
// Remix.res
module Loader = {
type t<'a> = unit => promise<'a>
}
module type LoaderData = {
type t
}
module MakeLoader = (Data: LoaderData) => {
type t = Loader.t<Data.t>
@module("@remix-run/react") external json: Data.t => 'b = "json"
@module("@remix-run/react")
external useLoaderData: unit => Data.t = "useLoaderData"
}
// _index.res
module Data = {
type t = {"foo": string, "data": array<string>}
}
module Loader = Remix.MakeLoader(Data)
let loader: Loader.t = async () => {
let data = async () =>
{
"foo": "bar",
"data": await Promise.resolve(["one"]),
}
Loader.json(await data()) // type error if this doesn't match Data.t
}
@react.component
let make = () => {
let data = Loader.useLoaderData() // type here is Data.t
<>
<Home_hero />
</>
}