GenType
genType
is a code generation tool that lets you export ReScript values and types to use in JavaScript, and import JavaScript values and types into ReScript.
Converter functions between the two representations are generated based on the type of the value. The converters can be generated in vanilla JavaScript, or in TypeScript / Flow for a type-safe idiomatic interface. In particular, conversion of rescript-react components both ways is supported, with automatic generation of the wrappers.
Here's an article describing how to use genType
as part of a migration strategy where a tree of components is gradually converted to ReScript bottom-up (old article containing Reason / BuckleScript): Adopting Reason: strategies, dual sources of truth, and why genType is a big deal.
The implementation of genType performs a type-directed transformation of ReScript programs after ReScript source code compilation. The transformed programs operate on data types idiomatic to JS.
For example, a ReScript function operating on a ReScript variant type t = | A(int) | B(string)
(which is represented as custom blocks at runtime) is exported to a JS function operating on the corresponding JS object of type { tag: "A"; value: number }
| { tag: "B"; value: string }
.
The output of genType can be configured by using one of 3 back-ends: untyped
to generate wrappers in vanilla JS, typescript
to generate TypeScript, and flow
to generate JS with Flow type annotations.
A Quick Example
Let's assume we are working on a TypeScript (TS) codebase and we want to integrate a single rescript-react component.
We want to be able to import the rescript-react component like any other React component in our existing TS code, but we also want to preserve all the ReScript types in the TS type system (and convert incompatible values if necessary).
That's exactly what genType was made for!
First we'll set up a rescript-react component:
RES/* src/MyComp.res */
@genType
type color =
| Red
| Blue;
@genType
@react.component
let make = (~name: string, ~color: color) => {
let colorStr =
switch (color) {
| Red => "red"
| Blue => "blue"
};
<div className={"color-" ++ colorStr}> {React.string(name)} </div>;
};
On a successful compile, genType
will convert src/MyComp.res
to a TS file called src/MyComp.gen.ts
which will look something like this:
TS// src/MyComp.gen.tsx
/* TypeScript file generated from MyComp.res by genType. */
/* eslint-disable import/first */
import * as React from 'react';
const $$toRE818596289: { [key: string]: any } = {"Red": 0, "Blue": 1};
// tslint:disable-next-line:no-var-requires
const MyCompBS = require('./MyComp.bs');
// tslint:disable-next-line:interface-over-type-literal
export type color = "Red" | "Blue";
// tslint:disable-next-line:interface-over-type-literal
export type Props = { readonly color: color; readonly name: string };
export const make: React.ComponentType<{ readonly color: color; readonly name: string }> = function MyComp(Arg1: any) {
const $props = {color:$$toRE818596289[Arg1.color], name:Arg1.name};
const result = React.createElement(MyCompBS.make, $props);
return result
};
genType automatically maps the color
variant to TS via a string union type color = "Red" | "Blue"
, and also provides all the converters to convert between the ReScript & TS representation as well.
Therefore way we can seamlessly use ReScript specific data structures within TS without writing the converter code by hand!
Within our TypeScript application, we can now import and use the React component in the following manner:
TS// src/App.ts
import { make as MyComp } from "./MyComp.gen.tsx";
const App = () => {
return (<div>
<h1> My Component </h1>
<MyComp color="Blue" name="ReScript & TypeScript" />
</div>);
};
That's it for our quick example.
For detailed information, head to the Getting Started or Usage section.
Development
For contributions, issues or questions, please refer to the GitHub repository or our ReScript forum.