How to pass a whole module as parameter?

In order to use Calendar component from react big calendar library I have to create a localizer like this using javascript :

import { Calendar, momentLocalizer } from 'react-big-calendar'
import moment from 'moment'

const localizer = momentLocalizer(moment) 

Now I want to do the same in Rescript so I first create a binding for momentLocalizer, with the help of bs-moment :

[@bs.module "react-big-calendar"]
external momentLocalizer: MomentRe.Moment.t => LocalizerT.t = "momentLocalizer";

Then I want to call it, but I don’t know how. I’ve tried to pass the Module as a value be it seems to need a constructor.

let localizer = ReactBigCalendarBindings.momentLocalizer(MomentRe.Moment);

I get the following message :

The variant constructor MomentRe.Moment can’t be found.

  • If it’s defined in another module or file, bring it into scope by:
    • Prefixing it with said module name: TheModule.MomentRe.Moment
    • Or specifying its type:
      let theValue: TheModule.theType = MomentRe.Moment
  • Constructors and modules are both capitalized. Did you want the latter?
    Then instead of let foo = Bar, try module Foo = Bar.

How do I pass momentLocalizer a module ?

You’d do something like this:

// Reason
type moment;
[@bs.module "moment"] external moment: moment = "default";

module Localizer = {
  type t;
};

module ReactBigCalendarBindings = {
  [@bs.module "react-big-calendar"]
  external momentLocalizer: moment => Localizer.t = "momentLocalizer";
};

let localizer = ReactBigCalendarBindings.momentLocalizer(moment);

Playground Link

Thank you, It does compile but I get an error at runtime

moment is not a function

Always check the JS output.
When compiled in ES6 mode, the output of the example above looks like this:

import Moment from "moment";
import * as ReactBigCalendar from "react-big-calendar";

var Localizer = {};

var ReactBigCalendarBindings = {};

var localizer = ReactBigCalendar.momentLocalizer(Moment);

This looks like the correct output according to the react-big-calendar README.

Actually the problem comes when I call the compoent, initializing localizer works fine. May be I should’ve start a new thread ?

I’ve reorganize the files and now the message is different.

Emmitter is not a constructor

Here is the code

// BsMoment.re
type moment;
[@bs.module "moment"] external moment: moment = "default";

// BsReactBigCalendar.re
module Localizer = {
type t;
};

type event = {
    title: string,
    start: string,
    _end: string,
    allDay: bool
};

[@bs.module "react-big-calendar"]
external momentLocalizer: BsMoment.moment => Localizer.t = "momentLocalizer";

module Calendar = {
    [@bs.module "react-big-calendar"][@react.component]
    external make : (
        ~startAccessor: string,
        ~endAccessor: string,
        ~localizer: Localizer.t,
        ~style: ReactDOM.Style.t,
        ~events: list(event)) => React.element = "Calendar";
}

// Index.re
let localizer = BsReactBigCalendar.momentLocalizer(BsMoment.moment);
ReactDOM.render(
    <BsReactBigCalendar.Calendar
        events={[]}
        startAccessor="start"
        endAccessor="end"
        localizer={localizer}
        style={ReactDOM.Style.make(~height="500px", ())} />, makeContainer());

// Index.bs.js
var localizer = ReactBigCalendar.momentLocalizer(Moment.default);
ReactDom.render(React.createElement(ReactBigCalendar.Calendar, {
    startAccessor: "start",
    endAccessor: "end",
    localizer: localizer,
    style: {
        height: "500px"
    },
    events: /* [] */0
}), makeContainer(undefined));

Running npm install react-big-calendar was not suffisant, I had to install manually some dependencies that I don’t have to when using react-big-calendar in classic react+js. (packages : emitter, popper, stream)
May be it has to do with dependencies not resolved ?

There is also this stange behavior, I pass an empty list to events and the compiler turns it to 0, any idea why ?

A list is a variant, so it mostly* follows the same rules as any other variant. Think of an empty list ([] in Reason, list{} in ReScript), as the name of a variant constructor. Just like any other variant constructor without a payload, it’s represented as an integer when it’s compiled.

*It’s a special variant defined by the compiler, so it does enjoy a few minor features that regular, user-defined, variants don’t.

To help understand what’s going on, compare the output of the built-in list type with a user-defined myCustomList type. They’re very similar!

With this in mind, list is not a shared data type, so you should probably never use it in an external binding. You need to use array, which is not the same thing.

3 Likes