This is the latest docs version
Quick Links
  • -Overview
  • -Language Features
  • -JS Interop
  • -Build System
Documentation
Language Manual
Reference for all language features
ReScript & React
First class bindings for ReactJS
GenType
Seamless TypeScript integration
Reanalyze
Dead Code & Termination analysis
Exploration
Packages
Explore third party libraries and bindings
Syntax Lookup
Discover all syntax constructs
APIPlaygroundBlogCommunity
  • Playground
  • Blog
  • X
  • Bluesky
  • GitHub
  • Forum
Language Manual
Overview
  • Introduction
  • Installation
  • Migrate to v11
  • Editor Plugins
  • Try
Language Features
  • Overview
  • Let Binding
  • Type
  • Primitive Types
  • Tuple
  • Record
  • Object
  • Variant
  • Polymorphic Variant
  • Null, Undefined and Option
  • Array & List
  • Function
  • If-Else & Loops
  • Pipe
  • Pattern Matching / Destructuring
  • Mutation
  • JSX
  • Exception
  • Lazy Value
  • Promises
  • Async / Await
  • Tagged templates
  • Module
  • Import & Export
  • Attribute (Decorator)
  • Reserved Keywords
  • Equality and Comparison
Advanced Features
  • Extensible Variant
  • Scoped Polymorphic Types
  • Module Functions
JavaScript Interop
  • Interop Cheatsheet
  • Embed Raw JavaScript
  • Shared Data Types
  • External (Bind to Any JS Library)
  • Bind to JS Object
  • Bind to JS Function
  • Import from / Export to JS
  • Bind to Global JS Values
  • JSON
  • Inlining Constants
  • Use Illegal Identifier Names
  • Generate Converters & Helpers
  • Browser Support & Polyfills
  • Libraries & Publishing
  • TypeScript
    • A Quick Example
    • Exporting an entire module
    • Setup
    • Testing the Whole Setup
    • Experimental features
    • Shims
    • Deprecated features
    • Limitations
Build System
  • Overview
  • Configuration
  • Configuration Schema
  • External Stdlib
  • Pinned Dependencies
  • Interop with JS Build Systems
  • Performance
  • Warning Numbers
Guides
  • Converting from JS
Extra
  • Newcomer Examples
  • Project Structure
  • FAQ
Docs / Language Manual / TypeScript
Edit

ReScript & TypeScript

The ReScript compiler includes a code generation tool that lets you export ReScript values and types to use in TypeScript, and import TypeScript values and types into ReScript. It is called "genType".

The implementation of genType performs a type-directed transformation of ReScript programs after compilation. The transformed programs operate on data types idiomatic to TypeScript.

For example, a ReScript variant (which is represented as custom objects with tags at runtime):

RES
@genType type t = | A(int) | B(string)

is exported to a TypeScript type:

TS
type t = { TAG: "A"; _0: number } | { TAG: "B"; _0: string };

A Quick Example

Let's assume we are working on a TypeScript codebase and we want to integrate a single ReScript function.

We want to be able to import the function like any other one in our existing TypeScript code, but we also want to preserve all the ReScript types in the TypeScript type system.

That's exactly what genType was made for!

First we'll set up a function:

RES
// src/Color.res @genType type color = | Red | Blue @genType let printColorMessage = (~color, ~message) => { let prefix = switch color { | Red => "\x1b[91m" | Blue => "\x1b[94m" } let reset = "\x1b[0m" Console.log(prefix ++ message ++ reset) }

On a successful compile, genType will convert src/Color.res to a TypeScript file called src/Color.gen.tsx which will look something like this:

TS
// src/Color.gen.tsx /* TypeScript file generated from Color.res by genType. */ /* eslint-disable */ /* tslint:disable */ import * as ColorJS from "./Color.res.js"; export type color = "Red" | "Blue"; export const printColorMessage: ( color: color ) => void = ColorJS.printColorMessage as any;

genType automatically maps the color variant to TS via a string union type "Red" | "Blue".

Within our TypeScript application, we can now import and use the function in the following manner:

TS
// src/app.ts import { printColorMessage } from "./Color.gen.tsx"; printColorMessage("Red", "Hello, genType!");

Exporting an entire module

Since ReScript 11.0.0 modules can be annotated with @genType as well. In that case, all types and values of the module will be converted to TS types. Example:

ReScriptTypeScript Output
@genType
module Size = {
  type t =
    | Small
    | Medium
    | Large

  let getNum = (size: t) =>
    switch size {
    | Small => 1.
    | Medium => 5.
    | Large => 10.
    }
}

Setup

Add a gentypeconfig section to your rescript.json (See Configuration for details).

Every genType powered project requires a configuration item "gentypeconfig" at top level in the project's rescript.json.

The minimal configuration of genType is following:

JSON
{ "gentypeconfig": { "module": "esmodule", "moduleResolution": "node", "generatedFileExtension": ".gen.tsx" } }

And don't forget to make sure allowJs is set to true in the project's tsconfig.json:

JSON
{ "compilerOptions": { "allowJs": true } }

TypeScript Module Resolutions

Make sure to set the same moduleResolution value in both rescript.json and tsconfig.json, so that the output of genType is done with the preferred module resolution.

For example if the TypeScript project uses JavaScript modules with Node16 / NodeNext module resolution:

JSON
// tsconfig.json { "compilerOptions": { "moduleResolution": "node16" } }

Then moduleResolution in gentypeconfig should be same value:

JSON
// rescript.json { "gentypeconfig": { "moduleResolution": "node16" } }

In case of the TypeScript project using Bundler module resolution, allowImportingTsExtensions should also be true:

JSON
// tsconfig.json { "compilerOptions": { "moduleResolution": "bundler", "allowImportingTsExtensions": true } }
JSON
// rescript.json { "gentypeconfig": { "moduleResolution": "bundler" } }

Testing the Whole Setup

Open any relevant *.res file and add @genType annotations to any bindings / values / functions to be used from JavaScript. If an annotated value uses a type, the type must be annotated too. See e.g. Hooks.res.

Save the file and rebuild the project via npm run res:build or similar. You should now see a *.gen.tsx file with the same name (e.g. MyComponent.res -> MyComponent.gen.tsx).

Any values exported from MyComponent.res can then be imported from TypeScript. For example:

JS
import MyComponent from "./components/MyComponent.gen.tsx";

Experimental features

These features are for experimentation only. They could be changed/removed any time, and not be considered breaking changes.

  • Export object and record types as interfaces. To activate, add "exportInterfaces": true to the configuration. The types are also renamed from name to Iname.

Shims

A shim is a TS file that provides user-provided definitions for library types.

Required only if one needs to export certain basic ReScript data types to JS when one cannot modify the sources to add annotations (e.g. exporting ReScript lists), and if the types are not first-classed in genType.

  • Example: Array<string> with format: "RescriptModule=JavaScriptModule"

Configure your shim files within "gentypeconfig" in your [rescript.json]:

JSON
{ "gentypeconfig": { "shims": { "Js": "Js", "ReactEvent": "ReactEvent", "RescriptPervasives": "RescriptPervasives", "ReasonReact": "ReactShim" }, }, }

and add relevant .shim.ts files in a directory which is visible by ReScript e.g.

├── rescript.json ├── src │ ├── shims │ │ ├── Js.shim.ts │ │ ├── ReactEvent.shim.ts │ │ └── RescriptPervasives.shim.ts

Here are some examples:

TS
// Excerpt from https://github.com/rescript-lang/rescript/blob/master/tests/gentype_tests/typescript-react-example/src/shims/Js.shim.ts export type Json_t = unknown; export type t = unknown;
TS
// Excerpt from https://github.com/rescript-lang/rescript/tree/master/tests/gentype_tests/typescript-react-example/src/shims/JsxEvent.shim.ts export type inputFocusEvent = React.FocusEvent<HTMLInputElement>;

More complete example shims can be found here.

Deprecated features

Features related to generating runtimes were deprecated since v11 and should no longer be used.

  • @genType("alias") and @genType.as("alias")

  • @genType.opaque

  • @genType.import

  • TypeScript Shims

genType does not generate anything runtime-related, and in the near future it generates definition files (*.d.ts) directly (See the roadmap).

If any runtime code is required for interoperability with JavaScript / TypeScript projects, it can be written by hand, or request a relevant features (e.g. @deriving) to the compiler.

Limitations

  • in-source = true. Currently only supports ReScript projects with in-source generation and file suffixes that end on .js, like .res.js or .bs.js.

  • Limited namespace support. Currently there's limited namespace support, and only namespace:true is possible, not e.g. namespace:"custom".

Libraries & PublishingOverview

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on