Modelling Interfaces in ReScript

I’m working on interfacing with some heavily inheritance based JS, and was wondering if I could somehow model the following scenario (in TS for typing):

type Thing;

interface HasThing {
  thing: Thing;
}

interface Item extends HasThing {
  thing: Thing;
  foo: Foo
}

const doThing: (thing: HasThing) => do(thing.thing);

I feel like functors are maybe the right path? But then how:

  1. Can I “appened” the thing field to a ReScript record type? Is it even possible?
  2. Can I “use” the functor type in my function signature?
  3. Can I combine many functors together (as this isn’t the only field like this)?

Ideally I don’t have to list every permutation, as it has just enough permutations to be both tedious and doItemThing seems frustrating to write.

Otherwise, this language has been a total dream :thumbsup:

1 Like

It would look something like:

type thing

module type HasThing = {
  let thing: thing
}

module type Item = {
  include HasThing
  let foo: foo
}

// Functor approach
module DoThing = (Thing: HasThing) => {
  do(Thing.thing)
}

// First-class module approach
let doThing = (thing: (module HasThing)) => {
  let (module Thing) = thing
  do(Thing.thing)
}

You can go with either approach.

  1. The thing field is inside a module type, so it can’t be appended to a record type
  2. Yes, see the first-class module approach above (you may need to tweak the syntax a bit, I’m not sure I got it totally right in ReScript syntax)
  3. If by ‘combine’ you mean the Thing functor argument can ‘inherit’ or ‘extend’ many interfaces, then yes you can, e.g.
module DoThing = (Thing: {
  include HasThing
  include HasOtherThing
  include HasSomethingElse
}) => {
  do(Thing.thing)
}

Same for the first-class module approach.

3 Likes