Movatterモバイル変換


[0]ホーム

URL:


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
@genTypetype 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@genTypetype color= |Red |Blue@genTypelet 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 convertsrc/Color.res to a TypeScript file calledsrc/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 *asColorJSfrom"./Color.res.js";export type color ="Red" |"Blue";exportconstprintColorMessage:(color: color) =>void =ColorJS.printColorMessageas any;

genType automatically maps thecolor 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.tsimport { printColorMessage }from"./Color.gen.tsx";printColorMessage("Red","Hello, genType!");

Exporting an entire module

Since ReScript11.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
@genTypemoduleSize = {type t=    |Small    |Medium    |Largelet getNum= (size: t)=>switch size {    |Small=>1.    |Medium=>5.    |Large=>10.    }}

Setup

Add agentypeconfig section to yourrescript.json (SeeConfiguration for details).

EverygenType powered project requires a configuration item"gentypeconfig" at top level in the project'srescript.json.

The minimal configuration of genType is following:

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

And don't forget to make sureallowJs is set totrue in the project'stsconfig.json:

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

TypeScript Module Resolutions

Make sure to set the samemoduleResolution value in bothrescript.json andtsconfig.json, so that the output of genType is done with the preferred module resolution.

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

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

ThenmoduleResolution ingentypeconfig should be same value:

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

In case of the TypeScript project usingBundler module resolution,allowImportingTsExtensions should also betrue:

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 vianpm 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 fromMyComponent.res can then be imported from TypeScript. For example:

JS
importMyComponentfrom"./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 fromname toIname.

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.tsexport typeJson_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.tsexport type inputFocusEvent =React.FocusEvent<HTMLInputElement>;

More complete example shims can be foundhere.

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 theroadmap).

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 within-source generation and file suffixes that end on.js, like.res.js or.bs.js.

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


[8]ページ先頭

©2009-2025 Movatter.jp