Type of external react component

Hello everyone!

In my project I have the following code:

module Minus = {
  @module("react-feather") @react.component
  external make: (~size: int=?) => React.element = "Minus"
}

module Square = {
  @module("react-feather") @react.component
  external make: (~size: int=?) => React.element = "Square"
}

module X = {
  @module("react-feather") @react.component
  external make: (~size: int=?) => React.element = "X"
}

<>
	<X size=15 />
	<Square size=15 />
	<Minus size=15 />
</>
->ignore

As you can see, every icon’s make function will have the same props so I’d like to move the signature into a separate type. Following code gives me an error:
This call is missing an argument of type (?size: option<int>)

type makeType = (~size: int=?) => React.element

module Minus = {
  @module("react-feather") @react.component
  external make: makeType = "Minus"
}

module Square = {
  @module("react-feather") @react.component
  external make: makeType = "Square"
}

module X = {
  @module("react-feather") @react.component
  external make: makeType = "X"
}

<>
	<X size=15 />
	<Square size=15 />
	<Minus size=15 />
</>
->ignore

Playground Link

How can I define that makeType without an error? If this is not the optimal way, what’s the best way here?

I assume the react.component macro is not capable of transforming type aliases to a labeled function.

You’d need to write that code without @react.component, e.g. like this:

module Shared = {
  type props
  type makeType = props => React.element

  @obj external makeProps: (~size: int=?, ~name: string=?, unit) => props = ""
}

module Minus = {
  include Shared

  @module("react-feather")
  external make: makeType = "Minus"
}

module Square = {
  include Shared

  @module("react-feather")
  external make: makeType = "Square"
}

module X = {
  include Shared

  @module("react-feather")
  external make: makeType = "X"
}

<> <X size=15 /> <Square size=15 name="test"/> <Minus size=15 /> </>->ignore

Playground Link

I personally find this code way more complex than necessary though, I’d probably rather duplicate props for each component as you did in your original example.

Thank you, the problem with duplication would be if I’d introduce a new param for a prop. Plus there’s a lot of icons which I potentially could use in the project.

That seems like a lot of code, is there a way for code gen here?

Unfortunately no.

You could write a small script that could code-gen the ReScript code you need as an Icons.res file? I guess this would be a one-time job to create this file anyways.

Quick sketch of what I mean:

// scripts/GenIcons.res
let icons = ["Minus", "Square", "X"] // you may get this data automatically from the module exports?

icons->Js.Array2.forEach(name => {

Js.log(`
module ${name} = {
  @module("react-feather")
  @react.component
  let make: (~size: int=?) => React.element = "${name}"
}
`)

})

compile that and then run node scripts/GenIcons.mjs > src/components/Icons.res.

1 Like

This might work! Thank you