module type Log = {
  type t
  let toString: t => string
}
let log = (content: 'a, logMod: module(Log with type t = 'a)) => {
  module LogMod = unpack(logMod) // here is not allowed, how to fix it?
  content->LogModule.toString->Js.log
}
log(
  "a",
  module(
    {
      type t = string
      let toString = v => v
    }
  ),
)
log(
  1,
  module(
    {
      type t = int
      let toString = v => v->Belt.Int.toString
    }
  ),
)
            You need to introduce a locally abstract type, eg type a.  Basically it introduces a type constructor named a that is abstract within its scope, and it gets replaced by a fresh type variable.  You can then use it in places where type variables are not allowed.  One example where this is not allowed is the one you found…in the first-class module with the abstract type.
You can use it like this (playground) :
// type a is locally abstract type
let log = (type a, content: a, log: module(Log with type t = a)) => {
  module Log = unpack(log)
  content->Log.toString->Js.log
}
And, btw, you can “unpack” the first-class module right in the function parameter to make it a bit more terse:
// Unpack in right in the function param...
let log' = (type a, content: a, module(Log: Log with type t = a)) => {
  content->Log.toString->Js.log
}
More reading…
- Here is a good explanation about the difference between the type variable and the locally abstract types
 - "generic" modules - #2 by yawaramin
 - Rescript advance types - escaping scope - #3 by johnj
 - How to use the first class module in rescript? - #9 by flo-pereira
 
              
              
              2 Likes