I was wondering how to define a type for node callback to use with external node functions. Starting from:
type nodeCallback = (Js.Nullable.t('e), Js.Nullable.t('a)) => unit;
Using error type 'e
does surely make it compatible with anything imaginable, but it becomes a problem if I try to convert it into a Belt.Result.t('a, exn)
(Because using exn in Result is both logical and convenient.). I can also trust that a proper node function will return an Error object (unlike some random js libs) so i am tempted to write:
type nodeCallback = (Js.Nullable.t(exn), Js.Nullable.t('a)) => unit;
However it turns out that:
- exn type must always contain an ocaml exception (affects its shape in js side too)
- Reason transpiling makes sure that js Error:s thrown inside reason try(…) expressions are magically converted into ocaml exceptions by processing them through
Caml_js_exceptions.internalToOCamlException
- Js.Exn.t is the type of these magically converted (js Error -> ocaml exn) errors.
exn | Js.Exn.Error(Js.Exn.t)
to be exact. - Using exn in nodeCallback type and then using nodeCallback type in some
[@bs...] external xyz: ...=> nodeCallback => unit = ""
declaration does not put the Error from the callback through the conversion function to become proper ocaml exn.
Is it a design decision that an explicit Js.Exn.Error constructor is not provided? Perhaps handling node callbacks could be done in some different way… Any ideas what would be the proper approach here?