- To have the module hierarchy, the submodules would actually need to be defined inside of a parent
ParentModulefile. For simple cases, just doing it inline usually suffices:
// ParentModule.res
module SubModule = {
//...
}
module AnotherOne = {
//...
}
If the sub modules end up becoming particularly large, one convention is to name them with their parent’s name separated by spaces:
ParentModule.res
ParentModule/
| ParentModule__SubModule.res
| ParentModule__AnotherOne.res
and then import the submodules into the file:
// ParentModule.res
module Submodule = ParentModule__SubModule
module AnotherOne = ParentModule__AnotherOne
- When you annotate the type of a module, you’re actually setting its public interface, hence why your first example causes the compiler to complain. If instead you want to have some minimum requirement, you could exploit the duck-typing of module parameters to force the compiler to check that your module satisfies the interface:
module type Foo = {
type t = string
}
module IsFoo = (F: Foo) => {}
module Bar = {
type t = string
// "extra" functionality
let baz = x => x + 2
}
// This will complain if Bar fails to satisfy Foo's interface
module BarIsFoo = IsFoo(Bar)