I think my problem is that having a module type intended for use by a Module Function, when having an abstract type, the Module Function only sees the abstract type as abstract (Ok that probably didn’t make any sense), a better explanation is in the comments
module type FunctorType = {
type a
// "type a = string" works but I want to set the type in MyMod
let injectedRun: a => unit
}
module Functor = (R: FunctorType) => {
let runInjectedRun = x => R.injectedRun(x)
}
module MyMod: FunctorType = {
type a = string // this is where I want to set the type
let injectedRun = (x: a) => Console.log(x)
}
module NewMod = Functor(MyMod)
NewMod.runInjectedRun("hello") // This has type: string But this function argument is expecting: MyMod.a
I think this is just simply this problem below. I’m probably wrongly thinking of MyModType as kind of a base module that has abstract members that need to be overwritten, but I guess that’s not how we do things around here.
module type MyModType = {
type a
}
module MyMod: MyModType = {
type a = int
}
let x: MyMod.a = 1 // This has type: int But it's expected to have type: MyMod.a
Just remove the FunctorType type annotation on MyMod
module MyMod = {
type a = string // this is where I want to set the type
let injectedRun = (x: a) => Console.log(x)
}
Modules are structurally typed. Using a module type annotation can therefore only remove information. You do not need to (and cannot) specify that MyMod implements or conforms with FunctorType.
It is possible to get this to work for concrete types while retaining the module type signature. It relies on explicitly setting the type of FunctorType.a in MyMod’s type signature.
You would need to create a differently named version of MyMod separately for each type you want to support.
module type FunctorType = {
type a
let injectedRun: a => unit
}
module Functor = (R: FunctorType) => {
let runInjectedRun = x => R.injectedRun(x)
}
// This is where you set an explicit type
// Specifying the a in FunctorType helps the compiler match things up
module MyMod: FunctorType with type a = string = {
type a = string
let injectedRun = (x: a) => Console.log(x)
}
module NewMod = Functor(MyMod)
NewMod.runInjectedRun("hello")
@glennsl has it right, you just need to remove the type annotations on the modules.
module type FunctorType = {
type a
// "type a = string" works but I want to set the type in MyMod
let injectedRun: a => unit
}
module Functor = (R: FunctorType) => {
let runInjectedRun = x => R.injectedRun(x)
}
module MyMod = {
type a = string // this is where I want to set the type
let injectedRun = (x: a) => Console.log(x)
}
module MyModInt = {
type a = int // this is where I want to set the type
let injectedRun = (x: a) => Console.log(x)
}
module NewMod = Functor(MyMod)
module NewModInt = Functor(MyModInt)
NewMod.runInjectedRun("hello")
NewModInt.runInjectedRun(42)