Typing cheerio.js?

Hey all, I have a question about how to properly type cheeriojs, specifically their syntax where you select an element. When you initiate cheeriojs, you do so through the cheerio.load function (no problem typing that), and then you use the returned class as either a function or an object. Here’s an example:

const $ = cheerio.load('<h1>Hello world</h1>')
// You can do this
// Or you can do this

I didn’t see anything in the docs that helped with this - maybe someone here has some ideas? Thanks!


You can have an identity function to convert from one form to other

eg: Playground

module Cheerio = {
  type t
  type tfunc = (. [#h1]) => string

  @module("cheerio") external load: string => t = "load"

  type element
  external html: t => element = "html"

  external toFunction: t => tfunc = "%identity"

let c = Cheerio.load("")

let html = c->Cheerio.html

let h1 = Cheerio.toFunction(c)(. #h1)


ReScript doesn’t have any built-in notion of “function with object properties” like JS does, but we can make this work cleanly with external bindings and some extra typing.

module Cheerio = {
  type element
  @send external text: (element, string) => string = "text"

  type cheerio
  type t<'a> = (. string) => element // This probably needs to be manually uncurried
  @module("cheerio") external load: string => t<cheerio> = "load"
  @send external html: t<cheerio> => string = "html"

// I'm using c since $ isn't valid ReScript
let c = Cheerio.load("<h1>Hello world</h1>")
let h1 = c(. "h1")->Cheerio.text("foo")
let html = Cheerio.html(c)

JavaScript output:

var Cheerio = require("cheerio");
var c = Cheerio.load("<h1>Hello world</h1>");
var h1 = c("h1").text("foo");
var html = c.html();

This is type-safe because of the abstract cheerio type. The t type is “just” a function, so we can execute it like any function. But because we can sign it with the cheerio type, which can only be created by the load function, we guarantee that only values created by load can be used with html.

I haven’t used cheerio myself, so I’m not sure what else you may need to do, but I hope that helps you get started with that aspect of it at least.