Note this is a change proposed for a major release.
Below is the motivation code:
module Foo = {
type navigationApi = {
one: [#1 | #2],
two: int,
}
let apiImpl: navigationApi = { one: #1, two: 2}
}
module type Foo = module type of Foo
let foo = module(Foo: Foo)
let baz: Foo.navigationApi = switch foo {
| module(Foo) => Foo.apiImpl
}
Some users wrote such code snippet and got a confusing error message:
[E] Line 13, column 17:
This has type: \"Foo/1017".navigationApi
Somewhere wanted: \"Foo/1002".navigationApi
The type constructor Foo/1017.navigationApi would escape its scope
The root cause is that module type of Foo
is not really Foo
's type, the type equivalence is lost, so user has to write this
module type Foo = module type of Foo with type navigationApi = Foo.navigationApi
If you have many types you can list it one by one, or use
module type Foo = module type of { include Foo}
IMHO, strengthen by default is a more intuitive semantics, so that in rescript we can desugar its module type of Foo
to such semantics.
Desugaring in syntax level is one way of implementation, we can also implement it in the type checking directly.