Exporting default with .rei is causing compiler error

I have a file which exports a react component and has an implementation file that looks like this

[@react.component]
let make: unit => React.element;

This works fine, but for JS interop using dynamic import I need my Re file to export default.

Added this to my Re file let default = make; like it’s explained in the docs but the compiler throws an error

  unused value default.

I tried to add a definition for default in the .rei

[@react.component]
let default: unit => React.element;

but it throws an error

The implementation /Users/x/code/app/src/components/tienda/Tienda.re
[0]        does not match the interface src/components/tienda/tienda-Sobras.cmi:
[0]        The value `defaultProps' is required but not provided
[0]        File "/Users/x/code/app/src/components/tienda/Tienda.rei", line 4, characters 0-53:
[0]          Expected declaration

Any idea how to work around this?

you probably don’t want to add the @react.component annotation, because this component is not supposed to be used in ReScript JSX anyways?

What happens if you don’t? I’d imagine you could do something like this?

import("./src/components/Tienda.bs", async tienda => {
  const Tienda = tienda.make;

  return <Tienda />;
})
1 Like

@yawaramin that was a good hint
I found in the docs that NextJS now has an example with named exports

this works

let TiendaHome = dynamic(() =>
  import('../components/tienda/TiendaHome.bs').then(
    (tienda) => tienda.make,
  ),
);
return <TiendaHome />;
1 Like

What if you directly name the implementation default? Then at least the .rei would match the .re.

.re:

[@react.component]
let default = () => React.string("Hello");

.rei:

[@react.component]
let default: unit => React.element;

Or, as @ryyppy suggested, just don’t use the @react.component annotation if you want to use the component from the JS side only.

.re:

let default = () => React.string("Hello");

.rei:

let default: unit => React.element;

in the first case with [@react.component] I get this error

We've found a bug for you!
[0]   .../src/components/tienda/TiendaHome.rei:4:1-5:34
[0]   
[0]   2 │ let make: unit => React.element;
[0]   3 │ 
[0]   4 │ [@react.component]
[0]   5 │ let default: unit => React.element;
[0]   
[0]   The implementation .../src/components/tienda/TiendaHome.re
[0]        does not match the interface src/components/tienda/tiendaHome-Sobras.cmi:
[0]        The value `defaultProps' is required but not provided
[0]        File ".../src/components/tienda/TiendaHome.rei", line 4, characters 0-53:
[0]          Expected declaration

and without react component I get

 We've found a bug for you!
[0]   .../src/components/tienda/TiendaHome.re:15:5-11
[0]   
[0]   13 │ };
[0]   14 │ 
[0]   15 │ let default = make;
[0]   
[0]   The implementation .../src/components/tienda/TiendaHome.re
[0]        does not match the interface src/components/tienda/tiendaHome-Sobras.cmi:
[0]        Values do not match:
[0]          let default: {. } => React.element
[0]        is not included in
[0]          let default: unit => React.element
[0]        File ".../src/components/tienda/TiendaHome.rei", line 4, characters 0-34:
[0]          Expected declaration
[0]        File ".../src/components/tienda/TiendaHome.re", line 15, characters 4-11:
[0]          Actual declaration

Your default export declaration in your rei should be defined as {.} => React.element, because @react.component converts unit props to an empty Js object prop instead

1 Like

In that case I get

 Values do not match:
[0]          let default: {. } => React.element
[0]        is not included in
[0]          let default: {. } => React.element

:man_shrugging:

Okay here is a complete example that works:

// Example.re

[@react.component]
let make = () => {
  <div/>
}

let default = make;
// Example.rei
let default: Js.t({.}) => React.element

The issue is that {.} is a special case where the compiler can’t decide if you are defining a Object, or a JS object.

In case you’d have a prop defined, you would be allowed to omit the Js.t part, e.g. {"name": string} => React.element, because this is implicitly converted to Js.t({"name": string}).

1 Like

ahhh, got it, very good to know. I’ll add it to my bag of tricks, thanks!

I get this error: The value make can't be found in Example

Playground link

EDIT: but exporting both default and make works. I had also forgotten that this was for use in JS, so default is what’s wanted there. Exporting make will ensure the component can also be used in ReScript code.

1 Like