Ah, now I see the misconception:
resi
files define the public interface for the res
file of the same name.
Fore example:
// A.resi
type x
let b: string
// A.res
type x = string
let a = "!"
let b = "Hi"++a
A.resi
defines the “shape” of the module A.res
, how it is perceived from the outside: There is a type called x
, which we don’t know the actual implementation of and there is a string value named b
. Because of the interface file, the value a
is not accessible from other modules.
It’s somehow similar to node’s module exports.
On the other hand, the module A.res
must implement everything, which is stated in A.resi
!
module type
is a “first class citizen” just like type
.
In your case you specify in the interface file Shared.resi
, that the module Shared.res
contains a module type Id
of the given shape.
But your actual implementation defines a module called UUID
and uses the module type Id
, which is not specified yet in the implementation.
So, you either want this:
// Shared.resi
module UUID: {
type t
let fromString: (~s: string) => t
let toString: (~id: t) => string
let generate: () => t
}
// Shared.res
module UUID = {
type t = string
let fromString = (~s) => s
let generate = () => fromString(~s=Uuid.V4.make())
let toString = (~id) => id
}
Or you define the module type in your implementation:
// Shared.resi
module type Id = {
type t
let fromString: (~s: string) => t
let toString: (~id: t) => string
let generate: () => t
}
module UUID: Id
// Shared.res
module type Id = {
type t
let fromString: (~s: string) => t
let toString: (~id: t) => string
let generate: () => t
}
module UUID = {
type t = string
let fromString = (~s) => s
let generate = () => fromString(~s=Uuid.V4.make())
let toString = (~id) => id
}
Defining a module type Id
makes sense, if you plan on having several modules implementing this interface.
Edit: Is there a text or wording in the docs, which you feel might have mislead you? Or should be improved for better understanding?