How to create a generic binding for useLoader and loader in Remix

Hello!

I’m experimenting with Rescript inside a Remix project (remix.run), the web framework from the React router folks. Is there a more interesting, fun way to enforce the types for these to functions without duplicating the types? See playground link for some light code.

More context: code snippet pulled from Remix | Loading Data.

export let loader: LoaderFunction = () => {
  return fetch("https://api.github.com/gists");
};

export default function Gists() {
  let data = useLoaderData(); // returns the value of loader

aside: :laughing: building up the possible ways to have generated type-safety in a rescript project from database to web framework will be my happy place to json would be my happy place. easy to setup new projects, throw away, iterate on new domains.

It’s been a while since I played with remix. But around that time, there wasn’t a good way to achieve this, and everyone seemed to build their solution to that problem (have a look at the issues around this in their repo, including my own proposal for infering the types) - the repo is private as of right now, but I think it will open up this week.

But I guess it would mainly depend on the types of the bindings that you can write for remix.

Maybe not that useful but I tried to create a new playground based on your input here.

1 Like

Thanks! Yes that’s basically it, but now it’d be nice to only annotate the type once.

I’ll take this, and see if I can use a module to do that.

You could use a functor:

module Make = (
  I: {
    type t
    let loader: unit => Js.Promise.t<t>
  },
) => {
  let loader = I.loader
  @module("remix") external useLoaderData: unit => I.t = "useLoaderData"
}

type gist = {id: int}

module Gists = Make({
  type t = array<gist>

  // you can fetch, etc. whatever here, the compiler will make
  // sure you return the right type
  let loader = () => Js.Promise.resolve([{id: 1}])
})

let loader = Gists.loader

let component = () => {
  let _data = Gists.useLoaderData()
}

For each page you’d make a new module specifying the page’s data type and loader function

Here’s a playground link for the above to see the types on hover and JS output

2 Likes

Nice, great use of a functor :clap: