GenType Usage
genType
operates on two kinds of entities: types and values.
Each can be exported from ReScript to JS, or imported into ReScript from JS.
The main annotation is @genType
, which by default means export.
Export and Import Types
The following exports a function type callback
to JS:
RES@genType
type callback = ReactEvent.Mouse.t => unit
To instead import a type called complexNumber
from JS module MyMath.ts
(or MyMath.js
), use the @genType.import
annotation:
RES@genType.import("./MyMath")
type complexNumber
This imported type will be treated as opaque by ReScript.
Export and Import Values
To export a function callback
to JS:
RES@genType
let callback = _ => Js.log("Clicked");
To rename the function and export it as CB
on the JS side, use
RES@genType
@genType.as("CB")
let callback = _ => Js.log("Clicked");
or the more compact
RES@genType("CB")
let callback = _ => Js.log("Clicked");
To import a function realValue
from JS module MyMath.ts
(or MyMath.js
):
RES@genType.import("./MyMath") /* JS module to import from. */
/* Name and type of the JS value to import. */
external realValue: complexNumber => float = "realValue";
Note: With genType < 2.17.0 or bucklescript < 5.0.0, one had to add a line with
@bs.module
and the current file name. See the older README.
Because of the external
keyword, it's clear from context that this is an import, so you can also just use @genType
and omit .import
.
To import a default JS export, use a second argument to @genType.import
e.g. @genType.import(("./MyMath", "default"))
.
Similarly, to import a value with a different JS name, use e.g. @genType.import(("./MyMath", "ValueStartingWithUpperCaseLetter"))
.
To import nested values, e.g. Some.Nested.value
, use e.g. @genType.import(("./MyMath", "Some.Nested.value"))
.
Interface (.resi) and Implementation (.res) files
If both Foo.resi
and Foo.res
exist, the annotations are taken from Foo.resi
. The same happens with local modules: if present, the module type gets precedence.
The behaviour can be overridden by adding annotation @genType.ignoreInterface
at the top of Foo.resi
. Use case: expose implementation details to JS but not to ReScript.
Type Expansion and @genType.opaque
If an exported type persons
references other types in its definition, those types are also exported by default, as long as they are defined in the same file:
REStype name = string
type surname = string
type person = {name: name, surname: surname}
@genType
type persons = array<person>;
If however you wish to hide from JS the fact that name
and surname
are strings, you can do it with the @genType.opaque
annotation:
RES@genType.opaque
type name = string
@genType.opaque
type surname = string
type person = {
name,
surname,
};
@genType
type persons = array<person>;
Renaming, @genType.as, and object mangling convention.
NOTE: Starting from ReScript 7.0.0, @genType.as
on record fields will be discouraged,
as it incurs a runtime conversion cost. Use a runtime free @as
instead.
NOTE: Starting from ReScript 11.0.0, the object mangling is removed.
By default, entities with a given name are exported/imported with the same name. However, you might wish to change the appearence of the name on the JS side.
For example, to use a reserved keyword type
as a record field:
RES@genType
type shipment = {
date: float,
@genType.as("type")
type_: string,
}
Object field names follow ReScript's mangling convention:
Remove trailing "__" if present. Otherwise remove leading "_" when followed by an uppercase letter, or keyword.
This means that the analogous example with objects is:
RES@genType
type shipment = {
"date": float,
"_type": string,
}
or the equivalent "type__": string
.
Functions and function components also follow the mangling convention for labeled arguments:
RES@genType
let exampleFunction = (~_type) => "type: " ++ _type
@genType
@react.component
let exampleComponent = (~_type) => React.string("type: " ++ _type)
It is possible to use @genType.as
for functions, though this is only maintained for backwards compatibility, and cannot be used on function components:
RES@genType
let functionWithGenTypeAs =
(~date: float) => @genType.as("type") (~type_: string) => ...
NOTE: For technical reasons, it is not possible to use @genType.as
on the first argument of a function.
Dependent Projects / Libraries
ReScript dependencies are specified in bs-dependencies
.
For example, if the dependencies are "bs-dependencies": ["somelibrary"]
and somelibrary
contains Common.res
, this looks up the types of foo
in the library:
RES@genType
let z = Common.foo;
Scoped packages of the form e.g. @demo/somelibrary
are also supported.
NOTE: The library must have been published with the .gen.ts
files created by genType.