diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index d226667ac..43a78c47a 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -51,7 +51,8 @@ "use-illegal-identifier-names", "generate-converters-accessors", "browser-support-polyfills", - "libraries" + "libraries", + "typescript-integration" ], "Build System": [ "build-overview", diff --git a/misc_docs/syntax/decorator_gentype.mdx b/misc_docs/syntax/decorator_gentype.mdx index 226678143..e585c5eec 100644 --- a/misc_docs/syntax/decorator_gentype.mdx +++ b/misc_docs/syntax/decorator_gentype.mdx @@ -1,20 +1,18 @@ --- id: "gentype-decorator" -keywords: ["gentype", "decorator", "typescript", "flow"] +keywords: ["gentype", "decorator", "typescript"] name: "@genType" summary: "This is the `@genType` decorator." category: "decorators" --- -The `@genType` decorator may be used to export ReScript values and types to JavaScript, and import JavaScript values and types into ReScript. It allows seamless integration of compiled ReScript modules in existing TypeScript, Flow, or plain JavaScript codebases, without loosing type information across different type systems. +The `@genType` decorator may be used to export ReScript values and types to JavaScript, and import JavaScript values and types into ReScript. It allows seamless integration of compiled ReScript modules in existing TypeScript, or plain JavaScript codebases, without losing type information across different type systems. -[GenType](/docs/gentype/latest/introduction) is a code generation tool for automatically generating [TypeScript](https://www.typescriptlang.org/) / [Flow](https://flow.org/) type definitions, and JS runtime converters for non-shared ReScript values. It also features first-class support for [ReasonReact](https://reasonml.github.io/reason-react/) components. - -**Note:** This decorator requires the `gentype` npm package to be installed and configured correctly. Please refer to genType's [Getting Started](/docs/gentype/latest/getting-started) section for more details. +[GenType](/docs/manual/latest/typescript-integration) is a code generation tool for automatically generating [TypeScript](https://www.typescriptlang.org/) type definitions, and JS runtime converters for non-shared ReScript values. It also features first-class support for [rescript-react](/docs/react/latest/introduction) components. ### Example - + ```res @genType @@ -59,45 +57,8 @@ export const make: React.ComponentType<{ }; ``` -```js -/** - * @flow strict - * @generated from MyComponent.res - * @nolint - */ -/* eslint-disable */ -// $FlowExpectedError: Reason checked type sufficiently -type $any = any; - -// $FlowExpectedError: Reason checked type sufficiently -import * as React from "react"; - -const $$toRE818596289 = { Red: 0, Blue: 1 }; - -// $FlowExpectedError: Reason checked type sufficiently -import * as MyComponentBS from "./MyComponent.bs"; - -export type color = "Red" | "Blue"; - -// Type annotated function components are not checked by Flow, but typeof() works. -const make$$forTypeof = function (_: {| - +color: color, - +name: string, -|}): React$Node { - return null; -}; - -export type Props = {| +color: color, +name: string |}; - -export const make: typeof make$$forTypeof = function MyComponent(Arg1: $any) { - const $props = { color: $$toRE818596289[Arg1.color], name: Arg1.name }; - const result = React.createElement(MyComponentBS.make, $props); - return result; -}; -``` - ### References -* [GenType](/docs/gentype/latest/introduction) +* [TypeScript Integration](/docs/manual/latest/typescript-integration) diff --git a/next.config.mjs b/next.config.mjs index a71ca6aed..bb2f92f7e 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -102,6 +102,26 @@ const config = { destination: "/docs/manual/v10.0.0/unboxed", permanent: true, }, + { + source: "/docs/gentype/latest/introduction", + destination: "/docs/manual/latest/typescript-integration", + permanent: true, + }, + { + source: "/docs/gentype/latest/getting-started", + destination: "/docs/manual/latest/typescript-integration", + permanent: true, + }, + { + source: "/docs/gentype/latest/usage", + destination: "/docs/manual/latest/typescript-integration", + permanent: true, + }, + { + source: "/docs/gentype/latest/supported-types", + destination: "/docs/manual/latest/typescript-integration", + permanent: true, + }, ]; }, }; diff --git a/pages/docs/gentype/latest/getting-started.mdx b/pages/docs/gentype/latest/getting-started.mdx deleted file mode 100644 index b5f6802b8..000000000 --- a/pages/docs/gentype/latest/getting-started.mdx +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: "Getting Started" -description: "How to get started with genType in your ReScript projects" -canonical: "/docs/gentype/latest/getting-started" ---- - -# Getting Started - -## Setup - -Since compiler v10.1, there's no need to install anything. For compiler 10.0 or older, install the binaries via `npm` (or `yarn`): - -``` -npm install gentype --save-dev - -# Verify installed gentype binary -npx gentype --help -``` - -Add a `gentypeconfig` section to your `rescript.json` (See [Configuration](#configuration) for details): - -``` -"gentypeconfig": { - "language": "typescript", - "shims": {}, - "generatedFileExtension": ".gen.tsx", - "module": "es6", - "debug": { - "all": false, - "basic": false - } -} -``` - -## Configuration - -Every `genType` powered project requires a configuration item `"gentypeconfig"` -at top level in the project's `rescript.json`. The configuration has following -structure: - -```js - //... - "gentypeconfig": { - "language": "typescript", - "generatedFileExtension": ".gen.tsx", - "module": "es6" | "commonjs", - "shims": { - "ReasonReact": "ReactShim" - } - } -``` - -- **generatedFileExtension** - - File extension used for genType generated files (defaults to `.gen.tsx`) - -- **language** - - `"typescript"` : the `language` setting is not required from compiler v10.1 - -- **module** - - Module format used for the generated `*.gen.tsx` files (supports `"es6"` and `"commonjs"`) - -- **shims** - - 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` with format: `"RescriptModule=JavaScriptModule"` - -## Adding Shims - -A shim is a TS file that provides user-provided definitions for library types. - -Configure your shim files within `"gentypeconfig"` in your [`rescript.json`](https://github.com/rescript-lang/rescript-compiler/blob/master/jscomp/gentype_tests/typescript-react-example/rescript.json), and add relevant `.shims.ts` files in a directory which is visible by ReScript e.g. [`src/shims/`](https://github.com/rescript-lang/rescript-compiler/tree/master/jscomp/gentype_tests/typescript-react-example/src/shims). An example shim to export ReactEvent can be found [here](https://github.com/rescript-lang/rescript-compiler/blob/master/jscomp/gentype_tests/typescript-react-example/src/shims/ReactEvent.shim.ts). - -## 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](https://github.com/reason-association/genType/blob/master/examples/typescript-react-example/src/Hooks.res). - -Save the file and rebuild the project via `npm run bs: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 JS. For example: - -```js -import MyComponent from "./components/MyComponent.gen"; -``` - -## Examples - -We prepared some examples to give you an idea on how to integrate `genType` in your own project. Check out the READMEs of the listed projects. - -- [typescript-react-example](https://github.com/rescript-lang/rescript-compiler/tree/master/jscomp/gentype_tests/typescript-react-example) - -## 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`. - -- Emit prop types for the untyped back-end. To activate, add `"propTypes": true` and `"language": "untyped"` to the configuration. - -## Limitations - -- **in-source = true**. Currently only supports ReScript projects with [in-source generation](/docs/manual/latest/build-configuration#package-specs) and `.bs.js` file suffix. - -- **Limited namespace support**. Currently there's limited [namespace](/docs/manual/latest/build-configuration#name-namespace) support, and only `namespace:true` is possible, not e.g. `namespace:"custom"`. diff --git a/pages/docs/gentype/latest/introduction.mdx b/pages/docs/gentype/latest/introduction.mdx deleted file mode 100644 index eed273bda..000000000 --- a/pages/docs/gentype/latest/introduction.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "Introduction" -description: "GenType - Interoperability between ReScript and TypeScript / Flow" -canonical: "/docs/gentype/latest/introduction" ---- - -# GenType - -`genType` is a code generation tool that lets you export ReScript values and types to use in TypeScript (TS), and import TS values and types into ReScript. - -Converter functions between the two runtime representations are generated when required based on the type of the values. -In particular, conversion of [rescript-react](/docs/react/latest/introduction) 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](https://medium.com/p/c514265b466d). - -The implementation of genType performs a type-directed transformation of ReScript programs after 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 objects with tags at runtime) is exported to a JS function operating on the corresponding JS object of type `{ tag: "A"; value: number } - | { tag: "B"; value: string }`. - -## A Quick Example - -Let's assume we are working on a TypeScript 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" - }; - -
{React.string(name)}
; -}; -``` - -On a successful compile, `genType` will convert `src/MyComp.res` to a TS file called `src/MyComp.gen.tsx` 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 (
-

My Component

- -
); -}; -``` - -That's it for our quick example. - -For detailed information, head to the [Getting Started](getting-started) or [Usage](usage) section. - -## Development - -Since ReScript v10.1, genType is part of the compiler's [GitHub repository](https://github.com/rescript-lang/rescript-compiler). diff --git a/pages/docs/gentype/latest/supported-types.mdx b/pages/docs/gentype/latest/supported-types.mdx deleted file mode 100644 index d1c5a77a5..000000000 --- a/pages/docs/gentype/latest/supported-types.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: "Supported Types" -description: "Supported types and value convertion in GenType" -canonical: "/docs/gentype/latest/supported-types" ---- - -# Supported Types - - - -Some types and values in ReScript do not map directly to JavaScript and need to be converted whenever a value crosses the boundary. This document gives an overview on how `genType`'s convertion works on different types. - - - -## Int - -ReScript values e.g. `1`, `2`, `3` are unchanged. So they are exported to JS values of type `number`. - -## Float - -ReScript values e.g. `1.0`, `2.0`, `3.0` are unchanged. So they are exported to JS values of type `number`. - -## String - -ReScript values e.g. `"a"`, `"b"`, `"c"` are unchanged. So they are exported to JS values of type `string`. - -## Optionals - -ReScript values of type e.g. `option`, such as `None`, `Some(0)`, `Some(1)`, `Some(2)`, are exported to JS values `null`, `undefined`, `0`, `1`, `2`. -The JS values are unboxed, and `null`/`undefined` are conflated. -So the option type is exported to JS type `null` or `undefined` or `number`. - -## Nullables - -ReScript values of type e.g. `Nullable.t`, such as `Nullable.null`, `Nullable.undefined`, `Nullable.make(0)`, `Nullable.make(1)`, `Nullable.make(2)`, are exported to JS values `null`, `undefined`, `0`, `1`, `2`. -The JS values are identical: there is no conversion unless the argument type needs conversion. - -## Records - -ReScript record values of type e.g. `{x: int}` such as `{x: 0}`, `{x: 1}`, are exported to JS values of type `{x: number}` without runtime conversion. - -Since records are immutable by default, their fields will be exported to readonly property types in Flow/TS. Mutable fields are specified in ReScript by e.g. `{mutable mutableField: string}`. - -The `@as` annotation can be used to change the name of a field on the JS side of things. So e.g. `{@as("y") x: int}` is exported as JS type `{y: number}`. - -If one field of the ReScript record has option type, this is exported to an optional JS field. So for example ReScript type `{x: option}` is exported as JS type `{x?: number}`. - -## Objects - -ReScript object values of type e.g. `{. "x":int}` such as `{"x": 0}`, `{"x": 1}`, `{"x": 2}`, are exported as identical JS object values `{x:0}`, `{x:1}`, `{x:2}`. This requires no conversion. So they are exported to JS values of type `{x:number}`. -A conversion is required only when the type of some field requires conversions. - -Since objects are immutable by default, their fields will be exported to readonly property types in Flow/TS. Mutable fields are specified in ReScript by e.g. `{ @set "mutableField": string }`. - -It is possible to mix object and option types, so for example the ReScript type `{. "x":int, "y":option}` exports to JS type `{x:number, ?y: string}`, requires no conversion, and allows option pattern matching on the ReScript side. - -## Tuples - -ReScript tuple values of type e.g. `(int, string)` are exported as identical JS values of type `[number, string]`. This requires no conversion, unless one of types of the tuple items does. -While the type of ReScript tuples is immutable, there's currently no mature enforcement in TS/Flow, so they're currenty exported to mutable tuples. - -## Variants - -Ordinary variants (with capitalized cases, e.g. ``` | A | B(int) ```) and polymorphic variants (with a backtick, e.g. ``` | `A | `B(int) ```) are represented in the same way, so there's no difference from the point of view of JavaScript. Polymorphic variants don't have to be capitalized. - -Variants can have an *unboxed*, or a *boxed* representation. The unboxed representation is used when there is at most one case with a payload, and that payload has object type; otherwise, a boxed representation is used. Object types are arrays, objects, records and tuples. - -Variants without payloads are essentially sequences of identifiers. -E.g. type ``@genType type days = Monday | Tuesday``. -The corresponding JS representation is `"Monday"`, `"Tuesday"`. -Similarly, polymorphic variant type ``@genType type days = [#Monday | #Tuesday]`` has the same JS representation. - - -When at most one variant case has a payload, and if the payload is of object type, e.g. -```Unnamed | Named({. "name": string, "surname": string})``` -then the representation is unboxed: JS values are e.g. `"Unnamed"` and -`{name: "hello", surname: "world"}`. Similarly for polymorphic variants. -Note that this unboxed representation does not use the label `"Named"` of the variant case with payload, because that value is distinguished from the other payload-less cases by its type: an object. - -If there is more than one case with payload, or if the single payload has not type object, a boxed representation is used. The boxed representation has shape ```{tag: "someTag", value: someValue}```. -For example, type ```| A | B(int) | C(string)``` has values such as ```"A"``` and -```{tag: "B", value: 42}``` and ```{tag: "C", value: "hello"}```. -Polymorhphic variants are treated similarly. Notice that payloads for polymorphic variants are always unary: ``` `Pair(int,int) ``` has a single payload of type `(int,int)`. Instead, ordinary variants distinguish between unary ``` Pair((int,int)) ``` and binary ``` Pair(int,int) ``` payloads. All those cases are represented in JS as ```{tag: "Pair", value: [3, 4]}```, and the conversion functions take care of the different ReScript representations. - -The `@genType.as` annotation can be used to modify the name emitted for a variant case on the JS side. So e.g. ``` | @genType.as("Arenamed") A``` exports ReScript value `` A `` to JS value `"Arenamed"`. -Boolean/integer/float constants can be expressed as ``` | @genType.as(true) True ``` and ``` | @genType.as(20) Twenty ``` and ``` | @genType.as(0.5) Half ```. Similarly for polymorphic variants. -The `@genType.as` annotation can also be used on variants with payloads to determine what appears in `{ tag: ... }`. - -For more examples, see [Variants.res](https://github.com/reason-association/genType/tree/master/examples/typescript-react-example/src/Variants.res) and [VariantsWithPayload.res](https://github.com/reason-association/genType/tree/master/examples/typescript-react-example/src/VariantsWithPayload.res). - -**NOTE:** When exporting/importing values that have polymorphic variant type, you have to use type annotations, and cannot rely on type inference. So instead of ```let monday = `Monday```, use ```let monday : days = `Monday```. The former does not work, as the type checker infers a type without annotations. - -## Arrays - -Arrays with elements of ReScript type `t` are exported to JS arrays with elements of the corresponding JS type. If a conversion is required, a copy of the array is performed. - -Immutable arrays are supported with the additional ReScript library -[ImmutableArray.res/.resi](https://github.com/reason-association/genType/tree/master/examples/typescript-react-example/src/ImmutableArray.resi), which currently needs to be added to your project. -The type `ImmutableArray.t<+'a>` is covariant, and is mapped to readonly array types in TS/Flow. As opposed to TS/Flow, `ImmutableArray.t` does not allow casting in either direction with normal arrays. Instead, a copy must be performed using `fromArray` and `toArray`. - -## Functions and Function Components - -ReScript functions are exported as JS functions of the corresponding type. -So for example a ReScript function `foo : int => int` is exported as a JS function from numbers to numbers. - -If named arguments are present in the ReScript type, they are grouped and exported as JS objects. For example `foo : (~x:int, ~y:int) => int` is exported as a JS function from objects of type `{x:number, y:number}` to numbers. - -In case of mixed named and unnamed arguments, consecutive named arguments form separate groups. So e.g. `foo : (int, ~x:int, ~y:int, int, ~z:int) => int` is exported to a JS function of type `(number, {x:number, y:number}, number, {z:number}) => number`. - -Function components are exported and imported exactly like normal functions. For example: - -```rescript -@genType -@react.component -let make = (~name) => React.string(name); -``` - -## Imported Types - -It's possible to import an existing TS/Flow type as an opaque type in ReScript. For example, - -```res -@genType.import("./SomeFlowTypes") type weekday -``` - -defines a type which maps to `weekday` in `SomeFlowTypes.js`. -See for example [Types.res](https://github.com/reason-association/genType/tree/master/examples/flow-react-example/src/Types.res) and [SomeFlowTypes.js](https://github.com/reason-association/genType/tree/master/examples/flow-react-example/src/SomeFlowTypes.js). - -## Recursive Types - -Recursive types which do not require a conversion are fully supported. -If a recursive type requires a conversion, only a shallow conversion is performed, and a warning comment is included in the output. (The alternative would be to perform an expensive conversion down a data structure of arbitrary size). -See for example [Types.res](https://github.com/reason-association/genType/tree/master/examples/typescript-react-example/src/nested/Types.res). - -## First Class Modules - -ReScript first class modules are converted from their array ReScript runtime representation to JS Object types. -For example, - -```res -module type MT = { - let x: int - let y: string -} -module M = { - let y = "abc" - let x = 42 -} - -@genType -let firstClassModule: module(MT) = module(M) -``` - -is exported as a JS object of type - -```res -{"x": number, "y": string} -``` - -Notice how the order of elements in the exported JS object is determined by the module type `MT` and not the module implementation `M`. - -## Polymorphic Types - -If a ReScript type contains a type variable, the corresponding value is not converted. In other words, the conversion is the identity function. For example, a ReScript function of type `{payload: 'a} => 'a` must treat the value of the payload as a black box, as a consequence of parametric polymorphism. If a typed back-end is used, the ReScript type is converted to the corresponding generic type. - -### Exporting Values from Polymorphic Types with Hidden Type Variables - -For cases when a value that contains a hidden type variable needs to be converted, a function can be used to produce the appropriate output: - -**Doesn't work** - -```res -@genType -let none = None -``` - -```js -export const none: ?T1 = OptionBS.none; // Errors out as T1 is not defined -``` - -**Works** - -```res -@genType -let none = () => None -``` - -```js -const none = (a: T1): ?T1 => OptionBS.none; -``` - -## Promises - -Values of type `Promise.t` are exported to JS promises of type `Promise` where `argJS` is the JS type corresponding to `arg`. -If a conversion for the argument is required, the conversion functions are chained via `.then(promise => ...)`. diff --git a/pages/docs/gentype/latest/usage.mdx b/pages/docs/gentype/latest/usage.mdx deleted file mode 100644 index b8744e31b..000000000 --- a/pages/docs/gentype/latest/usage.mdx +++ /dev/null @@ -1,183 +0,0 @@ -# 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 = _ => Console.log("Clicked"); -``` - -To rename the function and export it as `CB` on the JS side, use - -```res -@genType -@genType.as("CB") -let callback = _ => Console.log("Clicked"); -``` - -or the more compact - -```res -@genType("CB") -let callback = _ => Console.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](https://github.com/cristianoc/genType/blob/v2.16.0/README.md). - - - -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: - -```res -type name = string -type surname = string -type person = {name: name, surname: surname} - -@genType -type persons = array; -``` - -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; -``` - -## 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. diff --git a/pages/docs/manual/latest/build-configuration.mdx b/pages/docs/manual/latest/build-configuration.mdx index 9d73a8ffa..1588948a7 100644 --- a/pages/docs/manual/latest/build-configuration.mdx +++ b/pages/docs/manual/latest/build-configuration.mdx @@ -191,6 +191,42 @@ The warning numbers are shown in the build output when they're triggered. See [W Extra flags to pass to the compiler. For advanced usages. +## gentypeconfig + +To enable genType, set `"gentypeconfig"` at top level in the project's `rescript.json`. + +```json +{ + "gentypeconfig": { + "module": "es6", + "moduleResolution": "node", + "generatedFileExtension": ".gen.tsx", + "debug": { + "all": false, + "basic": false + } + } +} +``` + +`generatedFileExtension`: File extension used for genType generated files (defaults to `".gen.tsx"`) + +`module`: Module format used for the generated `*.gen.tsx` files (supports `"es6"` and `"commonjs"`) + +`moduleResolution`: Module resolution strategy used in genType outputs. This may be required for compatibility with TypeScript projects. Specify the value as the same in `tsconfig.json`. + +- `"node"`(default): Drop extensions in import paths. +- `"node16"`: Use TS output's extension. This provides compatibility with projects using `"moduleResolution": "node16"` and ES Modules. +- `"bundler"`: Use TS input's extension. This provides compatibility with projects using `"moduleResolution": "bundler"` and ES Modules. This also requires TS v5.0+ and `compilerOptions.allowImportingTsExtensions` to `true` + +`debug`: Enable debug logs. + +### Deprecated options + +`language`: the `language` setting is not required from compiler v10.1. + +`shims`: 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. + ## Environment Variables We heavily disrecommend the usage of environment variables, but for certain cases, they're justified. diff --git a/pages/docs/manual/latest/shared-data-types.mdx b/pages/docs/manual/latest/shared-data-types.mdx index 8f43f3964..530713b8d 100644 --- a/pages/docs/manual/latest/shared-data-types.mdx +++ b/pages/docs/manual/latest/shared-data-types.mdx @@ -41,4 +41,4 @@ Unlike most compiled-to-js languages, in ReScript, **you don't need to write dat Many of these are stable, which means that you can still serialize/deserialize them as-is without manual conversions. But we discourage actively peeking into their structure otherwise. -These types require manual conversions if you want to export them for JS consumption. For a seamless JS/TypeScript/Flow integration experience, you might want to use [genType](https://github.com/cristianoc/gentype) instead of doing conversions by hand. +These types require manual conversions if you want to export them for JS consumption. For a seamless JS/TypeScript integration experience, you might want to use [genType](https://github.com/cristianoc/gentype) instead of doing conversions by hand. diff --git a/pages/docs/manual/latest/typescript-integration.mdx b/pages/docs/manual/latest/typescript-integration.mdx new file mode 100644 index 000000000..7b8f8967f --- /dev/null +++ b/pages/docs/manual/latest/typescript-integration.mdx @@ -0,0 +1,234 @@ +--- +title: "TypeScript" +description: "GenType - Interoperability between ReScript and TypeScript" +canonical: "/docs/manual/latest/typescript-integration" +--- + +# 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: + + + +```res example +@genType +module Size = { + type t = + | Small + | Medium + | Large + + let getNum = (size: t) => + switch size { + | Small => 1. + | Medium => 5. + | Large => 10. + } +} +``` + +```ts +import * as MyCompBS__Es6Import from './MyComp.res'; +const MyCompBS: any = MyCompBS__Es6Import; + +export type Size_t = "Small" | "Medium" | "Large"; + +export const Size_getNum: (size:Size_t) => number = MyCompBS.Size.getNum; + +export const Size: { getNum: (size:Size_t) => number } = MyCompBS.Size +``` + + + +## Setup + +Add a `gentypeconfig` section to your `rescript.json` (See [Configuration](/docs/manual/latest/build-configuration#gentypeconfig) 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": "es6", + "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 ES 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](https://github.com/rescript-lang/rescript-compiler/blob/master/jscomp/gentype_tests/typescript-react-example/src/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`. + +## 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](https://github.com/rescript-lang/rescript-compiler/issues/6196)). + +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](/docs/manual/latest/build-configuration#package-specs) and file suffixes that end on `.js`, like `.res.js` or `.bs.js`. + +- **Limited namespace support**. Currently there's limited [namespace](/docs/manual/latest/build-configuration#name-namespace) support, and only `namespace:true` is possible, not e.g. `namespace:"custom"`. diff --git a/pages/docs/manual/v10.0.0/build-configuration.mdx b/pages/docs/manual/v10.0.0/build-configuration.mdx index debce5225..f91bd0c20 100644 --- a/pages/docs/manual/v10.0.0/build-configuration.mdx +++ b/pages/docs/manual/v10.0.0/build-configuration.mdx @@ -34,6 +34,7 @@ Your source files need to be specified explicitly (we don't want to accidentally "sources": ["src", "examples"] } ``` + ```json { "sources": { @@ -59,14 +60,14 @@ You can mark your directories as dev-only (for e.g. tests). These won't be built ```json { - "sources" : { - "dir" : "test", - "type" : "dev" + "sources": { + "dir": "test", + "type": "dev" } } ``` -You can also explicitly allow which modules can be seen from outside. This feature is especially useful for library authors who want to have a single entry point for their users. +You can also explicitly allow which modules can be seen from outside. This feature is especially useful for library authors who want to have a single entry point for their users. Here, the file `src/MyMainModule.res` is exposed to outside consumers, while all other files are private. ```json @@ -74,7 +75,7 @@ Here, the file `src/MyMainModule.res` is exposed to outside consumers, while all "sources": { "dir": "src", "public": ["MyMainModule"] - }, + } } ``` @@ -102,7 +103,7 @@ More details can be found on our [external stdlib](./build-external-stdlib) page ```json { - "reason": {"react-jsx": 3}, + "reason": { "react-jsx": 3 }, "refmt": 3 } ``` @@ -161,7 +162,7 @@ Generating JS files with the `.bs.js` suffix means that, on the JS side, you can - It's immediately clear that we're dealing with a generated JS file here. - It avoids clashes with a potential `theFile.js` file in the same folder. - It avoids the need of using a build system loader for ReScript files. This + in-source build means integrating a ReScript project into your pure JS codebase **basically doesn't touch anything in your build pipeline at all**. -- [genType](/docs/gentype/latest/introduction) requires `bs.js` for compiled JS artifacts. If you are using `genType`, you need to use `bs.js` for now. +- [genType](/docs/manual/latest/typescript-integration) requires `bs.js` for compiled JS artifacts. If you are using `genType`, you need to use `bs.js` for now. ## warnings diff --git a/pages/docs/manual/v9.0.0/build-configuration.mdx b/pages/docs/manual/v9.0.0/build-configuration.mdx index 5122093d0..6848c7dda 100644 --- a/pages/docs/manual/v9.0.0/build-configuration.mdx +++ b/pages/docs/manual/v9.0.0/build-configuration.mdx @@ -42,6 +42,7 @@ Your source files need to be specified explicitly (we don't want to accidentally "sources": ["src", "examples"] } ``` + ```json { "sources": { @@ -67,9 +68,9 @@ You can mark your directories as dev-only (for e.g. tests). These won't be built ```json { - "sources" : { - "dir" : "test", - "type" : "dev" + "sources": { + "dir": "test", + "type": "dev" } } ``` @@ -98,7 +99,7 @@ More details can be found on our [external stdlib](./build-external-stdlib) page ```json { - "reason": {"react-jsx": 3}, + "reason": { "react-jsx": 3 }, "refmt": 3 } ``` @@ -157,7 +158,7 @@ Generating JS files with the `.bs.js` suffix means that, on the JS side, you can - It's immediately clear that we're dealing with a generated JS file here. - It avoids clashes with a potential `theFile.js` file in the same folder. - It avoids the need of using a build system loader for ReScript files. This + in-source build means integrating a ReScript project into your pure JS codebase **basically doesn't touch anything in your build pipeline at all**. -- [genType](/docs/gentype/latest/introduction) requires `bs.js` for compiled JS artifacts. If you are using `genType`, you need to use `bs.js` for now. +- [genType](/docs/manual/latest/typescript-integration) requires `bs.js` for compiled JS artifacts. If you are using `genType`, you need to use `bs.js` for now. ## warnings diff --git a/pages/docs/react/latest/introduction.mdx b/pages/docs/react/latest/introduction.mdx index 8f6be8bd6..c5c1a7464 100644 --- a/pages/docs/react/latest/introduction.mdx +++ b/pages/docs/react/latest/introduction.mdx @@ -18,7 +18,7 @@ All our documented examples can be compiled in our [ReScript Playground](/try) a - Comes with all essential React APIs for building production ready apps (`useState`, `useReducer`, `useEffect`, `useRef`,...) - No component class API (all ReScript & React codebases are built on function components & hooks) - Strong level of type safety and type inference for component props and state values -- [GenType](/docs/gentype/latest/introduction) support for importing / exporting React components in TypeScript codebases +- [GenType](/docs/manual/latest/typescript-integration) support for importing / exporting React components in TypeScript codebases > **This documentation assumes basic knowledge about ReactJS.** > diff --git a/pages/docs/react/v0.10.0/introduction.mdx b/pages/docs/react/v0.10.0/introduction.mdx index cdbe5bf20..be12e58f5 100644 --- a/pages/docs/react/v0.10.0/introduction.mdx +++ b/pages/docs/react/v0.10.0/introduction.mdx @@ -18,7 +18,7 @@ All our documented examples can be compiled in our [ReScript Playground](/try) a - Comes with all essential React APIs for building production ready apps (`useState`, `useReducer`, `useEffect`, `useRef`,...) - No component class API (all ReScript & React codebases are built on functional components & hooks) - Strong level of type safety and type inference for component props and state values -- [GenType](/docs/gentype/latest/introduction) support for importing / exporting React components in Flow and TypeScript codebases +- [GenType](/docs/manual/latest/typescript-integration) support for importing / exporting React components in Flow and TypeScript codebases > **This documentation assumes basic knowledge about ReactJS.** > @@ -26,5 +26,5 @@ All our documented examples can be compiled in our [ReScript Playground](/try) a ## Development - - In case you are having any issues or if you want to help us out improving our bindings, check out our [rescript-react GitHub repository](https://github.com/rescript-lang/rescript-react). +- In case you are having any issues or if you want to help us out improving our bindings, check out our [rescript-react GitHub repository](https://github.com/rescript-lang/rescript-react). - For doc related issues, please go to the [rescript-lang.org repo](https://github.com/reason-association/rescript-lang.org). diff --git a/pages/docs/react/v0.11.0/introduction.mdx b/pages/docs/react/v0.11.0/introduction.mdx index 018041ad1..7c4747eb1 100644 --- a/pages/docs/react/v0.11.0/introduction.mdx +++ b/pages/docs/react/v0.11.0/introduction.mdx @@ -18,7 +18,7 @@ All our documented examples can be compiled in our [ReScript Playground](/try) a - Comes with all essential React APIs for building production ready apps (`useState`, `useReducer`, `useEffect`, `useRef`,...) - No component class API (all ReScript & React codebases are built on function components & hooks) - Strong level of type safety and type inference for component props and state values -- [GenType](/docs/gentype/latest/introduction) support for importing / exporting React components in TypeScript codebases +- [GenType](/docs/manual/latest/typescript-integration) support for importing / exporting React components in TypeScript codebases > **This documentation assumes basic knowledge about ReactJS.** > diff --git a/scripts/extract-tocs.mjs b/scripts/extract-tocs.mjs index f6d122c54..c83a57bff 100644 --- a/scripts/extract-tocs.mjs +++ b/scripts/extract-tocs.mjs @@ -274,32 +274,6 @@ const createReactToc = (version) => { fs.writeFileSync(TARGET_FILE, JSON.stringify(toc), "utf8"); }; -const createGenTypeToc = () => { - const MD_DIR = path.join(__dirname, "../pages/docs/gentype/latest"); - const SIDEBAR_JSON = path.join( - __dirname, - "../data/sidebar_gentype_latest.json" - ); - const TARGET_FILE = path.join( - __dirname, - "../index_data/gentype_latest_toc.json" - ); - - const sidebarJson = JSON.parse(fs.readFileSync(SIDEBAR_JSON)); - - const FILE_ORDER = Object.values(sidebarJson).reduce((acc, items) => { - return acc.concat(items); - }, []); - - const files = glob.sync(`${MD_DIR}/*.?(js|md?(x))`); - const ordered = orderFiles(files, FILE_ORDER); - - const result = ordered.map((filepath) => processFile(filepath, sidebarJson)); - const toc = createTOC(result); - - fs.writeFileSync(TARGET_FILE, JSON.stringify(toc), "utf8"); -}; - const createCommunityToc = () => { const MD_DIR = path.join(__dirname, "../pages/community"); const SIDEBAR_JSON = path.join(__dirname, "../data/sidebar_community.json"); @@ -344,5 +318,4 @@ createReasonCompilerToc(); createReactToc("latest"); createReactToc("v0.10.0"); createReactToc("v0.11.0"); -createGenTypeToc(); createCommunityToc(); diff --git a/src/DocsOverview.res b/src/DocsOverview.res index b4c212f8a..2193cdcae 100644 --- a/src/DocsOverview.res +++ b/src/DocsOverview.res @@ -36,7 +36,7 @@ let default = (~showVersionSelect=true) => { let ecosystem = [ ("Package Index", "/packages"), ("rescript-react", "/docs/react/latest/introduction"), - ("GenType", "/docs/gentype/latest/introduction"), + ("GenType", "/docs/manual/latest/typescript-integration"), ("Reanalyze", "https://github.com/reason-association/reanalyze"), ] diff --git a/src/common/App.res b/src/common/App.res index a6ca58227..335148b62 100644 --- a/src/common/App.res +++ b/src/common/App.res @@ -131,8 +131,6 @@ let make = (props: props): React.element => { } | {base: ["docs", "reason-compiler"], version: Latest} => content - | {base: ["docs", "gentype"], version: Latest} => - frontmatter}> content // common routes | {base} => switch Belt.List.fromArray(base) { diff --git a/src/common/Constants.res b/src/common/Constants.res index 7d9d9a9f8..21d492af3 100644 --- a/src/common/Constants.res +++ b/src/common/Constants.res @@ -20,7 +20,7 @@ let languageManual = version => { let ecosystem = [ ("Package Index", "/packages"), ("rescript-react", "/docs/react/latest/introduction"), - ("GenType", "/docs/gentype/latest/introduction"), + ("GenType", "/docs/manual/latest/typescript-integration"), ("Reanalyze", "https://github.com/reason-association/reanalyze"), ] diff --git a/src/components/Navigation.res b/src/components/Navigation.res index 02c83ab63..fe4bfb4aa 100644 --- a/src/components/Navigation.res +++ b/src/components/Navigation.res @@ -168,8 +168,8 @@ module DocsSection = { description: "Reference for all language features", href: `/docs/manual/${version}/introduction`, isActive: url => { - switch url.base { - | ["docs", "manual"] => true + switch url.fullpath { + | ["docs", "manual", _, fragment] => fragment !== "typescript-integration" | _ => false } }, @@ -189,11 +189,11 @@ module DocsSection = { { imgSrc: "/static/ic_gentype@2x.png", title: "GenType", - description: "Seamless TypeScript & Flow integration", - href: "/docs/gentype/latest/introduction", + description: "Seamless TypeScript integration", + href: "/docs/manual/latest/typescript-integration", isActive: url => { - switch url.base { - | ["docs", "gentype"] => true + switch url.fullpath { + | ["docs", "manual", _, "typescript-integration"] => true | _ => false } }, diff --git a/src/layouts/GenTypeDocsLayout.res b/src/layouts/GenTypeDocsLayout.res deleted file mode 100644 index 586377c8e..000000000 --- a/src/layouts/GenTypeDocsLayout.res +++ /dev/null @@ -1,46 +0,0 @@ -module LatestLayout = DocsLayout.Make({ - // Structure defined by `scripts/extract-tocs.js` - @module("index_data/gentype_latest_toc.json") external tocData: SidebarLayout.Toc.raw = "default" -}) - -@react.component -let make = (~frontmatter=?, ~components=MarkdownComponents.default, ~children) => { - let router = Next.Router.useRouter() - let route = router.route - - let url = route->Url.parse - - let version = switch url.version { - | Version(version) => version - | NoVersion => "latest" - | Latest => "latest" - } - - let breadcrumbs = list{ - { - open Url - {name: "Docs", href: "/docs/latest"} - }, - { - open Url - { - name: "GenType", - href: "/docs/gentype/" ++ (version ++ "/introduction"), - } - }, - } - - let title = "GenType" - let version = "v4" - - - children - -} diff --git a/src/layouts/GenTypeDocsLayout.resi b/src/layouts/GenTypeDocsLayout.resi deleted file mode 100644 index fd33938ba..000000000 --- a/src/layouts/GenTypeDocsLayout.resi +++ /dev/null @@ -1,6 +0,0 @@ -@react.component -let make: ( - ~frontmatter: Js.Json.t=?, - ~components: MarkdownComponents.t=?, - ~children: React.element, -) => React.element diff --git a/src/layouts/LandingPageLayout.res b/src/layouts/LandingPageLayout.res index 107483744..383195ce3 100644 --- a/src/layouts/LandingPageLayout.res +++ b/src/layouts/LandingPageLayout.res @@ -581,7 +581,7 @@ module CuratedResources = { imgSrc: "/static/ic_gentype@2x.png", title: React.string("TypeScript Integration"), descr: "Learn how to integrate ReScript in your existing TypeScript codebases.", - href: "/docs/gentype/latest/introduction", + href: "/docs/manual/latest/typescript-integration", }, ]