Understanding ReasonML types: React.element vs ReasonReact.component

mxdavis
Astrolabe Diagnostics

--

(for TL;DR on what this error means, click here)

I was tasked with building out notification banners for our app which is React front end, slowly converting from Flow to ReasonReact.

I created the new ReasonReact Notification component and nested it into a Flow component by importing the bs.js file and it displayed the notifications beautifully. 🎉

The issues started when I tried rendering the notifications into an existing Reason component. The first warning I got was:

Error: This expression has type array('a)but an expression was expected of type {. }

Super clear, I know.

Then I realized my VS code merlin extension was not working properly, so I fixed that up, and now the error was better:

Error: This expression has type 'a => React.elementbut an expression was expected of typeReasonReact.component('b, 'c, 'd) =ReasonReact.componentSpec('b, 'b, 'c, 'c, 'd)

Well, sort of clearer, but still was unsure what I was doing wrong this time. I googled but could not find much difference between a React.element and a ReasonReact.component and they were both.re files, why would one be React and the other ReasonReact. The other thing bugging me was this component was rendering other components fine but was only getting angry with the new Notification component. 🧐

I headed to the Reason discord channel and decided to try my luck there, posted the error, along with the important parts of the Notification component (or so I thought):

The friendly ReasonML discord chat tried helping me right away, but since I was not aware of what was breaking it, and was not giving all the necessary details, I was just being thrown in a loop trying their suggestions.

I decided to try from the beginning to see what could be the one line breaking everything. I created a dummy.re file in the same location as the Notification component (just in case it was a directory problem):

Low and behold, the same issue. This had nothing to do with any functionality in the Notification component. I started to compare line by line the component I was importing into, and the Notification component. And suddenly realized there was an important line that I missed posting in the snippet on discord, the Notification component had [@bs.config {jsx: 3}]; on the very first line, and the component I was trying to import it into did not.

(Now for the TL;DR of this article)

Now things started clicking. React.element is a ReasonReact JSX: 3 component, and ReasonReact.component(‘b, ‘c, ‘d) is a ReasonReact JSX: 2 component. The JSX 2 component was expecting a JSX2 component, and it was getting a JSX3 component.

This explains why the Flow component nested the Notification component without issue, it does not care about the ReasonReact version, it uses the bs.js file.

OK, now Reason Error has been deciphered and I updated the ReasonReact JSX2 to JSX3 (that can be its blog post in of itself) and now the Notifications started appearing, and life is great! Even Merlin is happy! 😃

--

--