Newcomer confusion about library imports and types

Hi all,

Mega newb here, just started looking into ReScript, looking to setup a next app which so far has been going pretty smoothly (besides the use client directive, but very happy to know is pending next release!).

The bit where I am a little lost is on the import of node_modules and related types.

Say i want to import lodash.camelcase, and its related types for use in my ReScript code.

I know I can create a .res file with the following

@module("lodash.camelcase") external camel_case: string => string = "default"

This allows me to write (in a react component for example)

let str = camel_case("some testing string")

And it seems to compile just fine, however when running the application I get told that LodashCamelCase is not a function :thinking:

Also being lodash.camelcase a trivial function used for example it is pretty easy to type it manually, buy ultimately in more complex cases would be great to be able to reuse the TS types where available. I did read on the doc site that @gentype could be used for this purpose, but am unsure as to how to go about it, my initial tests didn’t output very useful stuff.

Is there any resource with a fairly end to end example (or even better a GitHub repo) I should peek at?

Any help appreciated and apologies for the formatting, I wrote this on the phone :slight_smile:

1 Like

what does the compiled js look like? can you show me where its getting “LodashCamelCase”?

Interestingly, here is the compiled JS:

// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';

var LodashCamelcase = require("lodash.camelcase").default;
var JsxRuntime = require("react/jsx-runtime");

function Index$default(props) {
  return JsxRuntime.jsx("main", {
              children: JsxRuntime.jsx("div", {
                    children: LodashCamelcase("some testing string")
                  })
            });
}

var $$default = Index$default;

exports.$$default = $$default;
exports.default = $$default;
exports.__esModule = true;
/* lodash.camelcase Not a pure module */

It does seem to make a little mess of the exports :confused:

Changing package-specs.module to es6 seems to fix the import however:

// Generated by ReScript, PLEASE EDIT WITH CARE

import * as React from "react";
import LodashCamelcase from "lodash.camelcase";

function Index$default(props) {
  return React.createElement("main", undefined, React.createElement("div", undefined, LodashCamelcase("some testing string")));
}

var $$default = Index$default;

export {
  $$default ,
  $$default as default,
}
/* react Not a pure module */

I guess I could just call it a day but I’d like to understand better, in particular as I might have to wrangle libraries with a mix of CJS and ESM in this project :grimacing:

So when the output is set to es6 all seems good but not on commonjs so I did another small test, created a small utils file with a default and named export and test both build configs. As expected ES6 works just fine:

Bindings

@module("../utils/index.js")
external logDefault: () => unit = "default"


@module("../utils/index.js")
external logNamed: () => unit = "logNamed"

ES6

const logDefault = function () {
    console.log('this is a default export')
}

export const logNamed = function () {
    console.log('this is a named export')
}

export default logDefault

→ this is a default export
→ this is a named export

All good!

CJS

Different story, I can’t seem to get the imports to work as commonjs at all.

const logDefault = function () {
    console.log('this is a default export')
}

const logNamed = function () {
    console.log('this is a named export')
}

exports.logNamed = logNamed;
module.exports = logDefault

→ Error

Uncaught TypeError: IndexJs$1 is not a function
    at Object.logDefault
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';

var IndexJs = require("../utils/index.js");
var IndexJs$1 = require("../utils/index.js").default;

function logDefault(prim) {
  IndexJs$1();
}

function logNamed(prim) {
  IndexJs.logNamed();
}

exports.logDefault = logDefault;
exports.logNamed = logNamed;
/* ../utils/index.js Not a pure module */

Thoughts?