I’m finding the module signature docs very confusing. There’s a lot of mentions about module type, but there hardly any mention of files until we come to the .resi extension.
What I’m wondering if I always need a .resi file to hide certain methods. For example, I’ve written a very simple binding to the Chance npm module.
Chance.res
type t
@new @module external make: unit => t = "Chance"
@send external getBoolLikelihood: (t, {"likelihood": int}) => bool = "bool"
let getBool = (~likelihood=50, ()) => {
let c = make()
c->getBoolLikelihood({"likelihood": likelihood})
}
I use it here in Demo.res
let r = Chance.getBool()
Js.log(r)
I have a interface file to hide everything except getBool()
Chance.resi
let getBool: (~likelihood: int=?, unit) => bool
My concern is I don’t want .resi files all over the place. Is there not a way to make things private in the .res file itself.
The docs keep mention things like this
module type EstablishmentType = {
type profession
let getProfession: profession => string
}
But I can’t tell if that has a relation to files or its just an non-practical example of just defining an interface local to a filie.
Unfortunately on the .res level you’d need a .resi file. If it would have been a nested module, you could have used module types to constraint the interface of your module.
There’s also a less common way with the %%private extension, that has its own trade-offs on the IDE side. For hiding externals it’s sometimes useful:
type t
%%private(
@new @module external make: unit => t = "Chance"
@send external getBoolLikelihood: (t, {"likelihood": int}) => bool = "bool"
)
let getBool = (~likelihood=50, ()) => {
let c = make()
c->getBoolLikelihood({"likelihood": likelihood})
}
It’s normal and expected to have .resi files for many or most of your .res files. They help with not just hiding private members but also with compile times and checking for accidental API changes.
You can use the new npx rescript dump src/path/App-ProjectName.cmi > ./src/path/App.resi command to generate a .resi file to save some steps.
It’s looking for files in your ./lib/bs directory but without that prefix, I don’t like that user can’t use tab completion to navigate these files but at least the command works. ProjectName is PascalCase version of the name attribute in your bsconfig.json
OK I can live with that, but is it ok to just move them into their own folder? And would I name the folder Chance, chance, chance_binding? Is there a convention for that now?
Would be cool if the compiler created a hidden one for you, as long as you didn’t create one yourself. That would only be feasible without PPX intervention, though.
But If we had both private submodules and this, the need for manually creating .resi files would only be there for documentation purposes anymore.