Type redundancy between module signature .resi and modules .res

Currently types defined in signature file .resi are not accessible from modules .res with same name, this forces code duplication by forcing to define the type twice for the same module, which feels awkward coming from typescript were .d.ts files allow to define types only once, before someone mentions in comments that this is the expected way rescript works, think that implies that redundancy is an okay thing to accept

I don’t think .d.ts files are a fair comparison to OCaml’s signature files (.mli). They serve different purposes, as far as I can tell. ReScript has its roots in OCaml, and signature files are a testament to that.

The proposal Private by Default could potentially reduce the need for an additional file to hide implementation details, but it’s unlikely to happen in the short term.

This is likely an area that’s best solved by improving the editor tooling (making it easy to see what’s missing between res/resi, and making it easy to update/copy types).

of course, if you use your types exactly the same way both inside and outside, this looks like useless duplication, but there are many cases where the types are not the same, you could have for example a record in your implementation and an opaque or private type in your interface.

As @zth said, there are things we could improve around editor tooling for this.

Meanwhile, there’s a strategy that can work well for the files where you have a lot of identical types in your implementation and interface files, let’s say you have a file A.res, you can create an ATypes.res where you’d define those types and you’d include it both in A.res and A.resi:

module ATypes = {
  type foo = {
    bar: int,
    baz: string,
    // ...
  }
  type bazz = {
    foo: foo,
    barr: int,
    // ...
  }

  // ...
}

module A: {
  include module type of ATypes
  let foo: (int, string) => foo
} = {
  include ATypes
  let foo = (bar, baz) => {bar, baz}
}

Playground link

2 Likes