From f6434e7fddef2b9f97d1a33e01b7c931e14564fd Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Tue, 5 Dec 2023 09:41:53 +0100 Subject: [PATCH 01/11] Integrate genType as 'TypeScript Interop' chapter into main docs --- data/sidebar_manual_latest.json | 6 +++ misc_docs/syntax/decorator_gentype.mdx | 49 ++----------------- next.config.mjs | 20 ++++++++ .../latest/gentype-getting-started.mdx} | 4 +- .../latest/gentype-introduction.mdx} | 6 +-- .../latest/gentype-supported-types.mdx} | 16 +++--- .../latest/gentype-usage.mdx} | 8 ++- .../docs/manual/latest/shared-data-types.mdx | 2 +- .../manual/v10.0.0/build-configuration.mdx | 2 +- .../manual/v9.0.0/build-configuration.mdx | 2 +- pages/docs/react/latest/introduction.mdx | 2 +- pages/docs/react/v0.10.0/introduction.mdx | 4 +- pages/docs/react/v0.11.0/introduction.mdx | 2 +- scripts/extract-tocs.mjs | 27 ---------- src/DocsOverview.res | 2 +- src/common/App.res | 2 - src/common/Constants.res | 2 +- src/components/Navigation.res | 12 ++--- src/layouts/GenTypeDocsLayout.res | 46 ----------------- src/layouts/GenTypeDocsLayout.resi | 6 --- src/layouts/LandingPageLayout.res | 2 +- 21 files changed, 67 insertions(+), 155 deletions(-) rename pages/docs/{gentype/latest/getting-started.mdx => manual/latest/gentype-getting-started.mdx} (98%) rename pages/docs/{gentype/latest/introduction.mdx => manual/latest/gentype-introduction.mdx} (94%) rename pages/docs/{gentype/latest/supported-types.mdx => manual/latest/gentype-supported-types.mdx} (92%) rename pages/docs/{gentype/latest/usage.mdx => manual/latest/gentype-usage.mdx} (96%) delete mode 100644 src/layouts/GenTypeDocsLayout.res delete mode 100644 src/layouts/GenTypeDocsLayout.resi diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index d226667ac..64140a108 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -53,6 +53,12 @@ "browser-support-polyfills", "libraries" ], + "TypeScript Interop": [ + "gentype-introduction", + "gentype-getting-started", + "gentype-usage", + "gentype-supported-types" + ], "Build System": [ "build-overview", "build-configuration", diff --git a/misc_docs/syntax/decorator_gentype.mdx b/misc_docs/syntax/decorator_gentype.mdx index 226678143..52f976187 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/gentype-introduction) 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) +* [GenType](/docs/manual/latest/gentype-introduction) diff --git a/next.config.mjs b/next.config.mjs index a71ca6aed..804fb6c90 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/gentype-introduction", + permanent: true, + }, + { + source: "/docs/gentype/latest/getting-started", + destination: "/docs/manual/latest/gentype-getting-started", + permanent: true, + }, + { + source: "/docs/gentype/latest/usage", + destination: "/docs/manual/latest/gentype-usage", + permanent: true, + }, + { + source: "/docs/gentype/latest/supported-types", + destination: "/docs/manual/latest/gentype-supported-types", + permanent: true, + }, ]; }, }; diff --git a/pages/docs/gentype/latest/getting-started.mdx b/pages/docs/manual/latest/gentype-getting-started.mdx similarity index 98% rename from pages/docs/gentype/latest/getting-started.mdx rename to pages/docs/manual/latest/gentype-getting-started.mdx index b5f6802b8..af463fbff 100644 --- a/pages/docs/gentype/latest/getting-started.mdx +++ b/pages/docs/manual/latest/gentype-getting-started.mdx @@ -1,10 +1,10 @@ --- title: "Getting Started" description: "How to get started with genType in your ReScript projects" -canonical: "/docs/gentype/latest/getting-started" +canonical: "/docs/manual/latest/gentype-getting-started" --- -# Getting Started +# GenType - Getting Started ## Setup diff --git a/pages/docs/gentype/latest/introduction.mdx b/pages/docs/manual/latest/gentype-introduction.mdx similarity index 94% rename from pages/docs/gentype/latest/introduction.mdx rename to pages/docs/manual/latest/gentype-introduction.mdx index eed273bda..2aedbd3ef 100644 --- a/pages/docs/gentype/latest/introduction.mdx +++ b/pages/docs/manual/latest/gentype-introduction.mdx @@ -1,7 +1,7 @@ --- title: "Introduction" -description: "GenType - Interoperability between ReScript and TypeScript / Flow" -canonical: "/docs/gentype/latest/introduction" +description: "GenType - Interoperability between ReScript and TypeScript" +canonical: "/docs/manual/latest/gentype-introduction" --- # GenType @@ -98,7 +98,7 @@ const App = () => { That's it for our quick example. -For detailed information, head to the [Getting Started](getting-started) or [Usage](usage) section. +For detailed information, head to the [Getting Started](/docs/manual/latest/gentype-getting-started) or [Usage](/docs/manual/latest/gentype-usage) section. ## Development diff --git a/pages/docs/gentype/latest/supported-types.mdx b/pages/docs/manual/latest/gentype-supported-types.mdx similarity index 92% rename from pages/docs/gentype/latest/supported-types.mdx rename to pages/docs/manual/latest/gentype-supported-types.mdx index d1c5a77a5..39a3795a6 100644 --- a/pages/docs/gentype/latest/supported-types.mdx +++ b/pages/docs/manual/latest/gentype-supported-types.mdx @@ -1,10 +1,10 @@ --- title: "Supported Types" -description: "Supported types and value convertion in GenType" -canonical: "/docs/gentype/latest/supported-types" +description: "Supported types and value conversion in GenType" +canonical: "/docs/manual/latest/gentype-supported-types" --- -# Supported Types +# GenType - Supported Types @@ -39,7 +39,7 @@ The JS values are identical: there is no conversion unless the argument type nee 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}`. +Since records are immutable by default, their fields will be exported to readonly property types in 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}`. @@ -50,14 +50,14 @@ If one field of the ReScript record has option type, this is exported to an opti 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 }`. +Since objects are immutable by default, their fields will be exported to readonly property types in 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. +While the type of ReScript tuples is immutable, there's currently no mature enforcement in TS, so they're currenty exported to mutable tuples. ## Variants @@ -96,7 +96,7 @@ Arrays with elements of ReScript type `t` are exported to JS arrays with element 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`. +The type `ImmutableArray.t<+'a>` is covariant, and is mapped to readonly array types in TS. As opposed to TS, `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 @@ -117,7 +117,7 @@ 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, +It's possible to import an existing TS type as an opaque type in ReScript. For example, ```res @genType.import("./SomeFlowTypes") type weekday diff --git a/pages/docs/gentype/latest/usage.mdx b/pages/docs/manual/latest/gentype-usage.mdx similarity index 96% rename from pages/docs/gentype/latest/usage.mdx rename to pages/docs/manual/latest/gentype-usage.mdx index b8744e31b..36b114634 100644 --- a/pages/docs/gentype/latest/usage.mdx +++ b/pages/docs/manual/latest/gentype-usage.mdx @@ -1,4 +1,10 @@ -# Usage +--- +title: "Usage" +description: "GenType - Interoperability between ReScript and TypeScript" +canonical: "/docs/manual/latest/gentype-usage" +--- + +# GenType Usage 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/v10.0.0/build-configuration.mdx b/pages/docs/manual/v10.0.0/build-configuration.mdx index debce5225..c1f1e5d9d 100644 --- a/pages/docs/manual/v10.0.0/build-configuration.mdx +++ b/pages/docs/manual/v10.0.0/build-configuration.mdx @@ -161,7 +161,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/gentype-introduction) 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..3cf1ab936 100644 --- a/pages/docs/manual/v9.0.0/build-configuration.mdx +++ b/pages/docs/manual/v9.0.0/build-configuration.mdx @@ -157,7 +157,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/gentype-introduction) 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..610ab1c83 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/gentype-introduction) 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..c3f3c1057 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/gentype-introduction) 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..9e4eff3f7 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/gentype-introduction) 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..2e6f47825 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/gentype-introduction"), ("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..c6bc22cd0 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/gentype-introduction"), ("Reanalyze", "https://github.com/reason-association/reanalyze"), ] diff --git a/src/components/Navigation.res b/src/components/Navigation.res index 02c83ab63..4299ba3e5 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->Js.String2.startsWith("gentype")) | _ => 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/gentype-introduction", isActive: url => { - switch url.base { - | ["docs", "gentype"] => true + switch url.fullpath { + | ["docs", "manual", _, fragment] => fragment->Js.String2.startsWith("gentype") | _ => 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..ad9c1c721 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/gentype-introduction", }, ] From dd65d81e8ee21342a79ee62124805521266f5623 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Tue, 5 Dec 2023 11:43:16 +0100 Subject: [PATCH 02/11] WIP: 4d7cc304 Merge pull request #750 from rescript-association/uncurried-docs --- .../manual/latest/build-configuration.mdx | 1 + .../manual/latest/gentype-getting-started.mdx | 102 ------------ .../manual/latest/gentype-introduction.mdx | 151 ++++++++++++++---- 3 files changed, 121 insertions(+), 133 deletions(-) delete mode 100644 pages/docs/manual/latest/gentype-getting-started.mdx diff --git a/pages/docs/manual/latest/build-configuration.mdx b/pages/docs/manual/latest/build-configuration.mdx index 9d73a8ffa..485753177 100644 --- a/pages/docs/manual/latest/build-configuration.mdx +++ b/pages/docs/manual/latest/build-configuration.mdx @@ -149,6 +149,7 @@ one of the following: - `".res.js"` - `".res.mjs"` - `".res.cjs"` + <<<<<<< HEAD ### Design Decisions diff --git a/pages/docs/manual/latest/gentype-getting-started.mdx b/pages/docs/manual/latest/gentype-getting-started.mdx deleted file mode 100644 index af463fbff..000000000 --- a/pages/docs/manual/latest/gentype-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/manual/latest/gentype-getting-started" ---- - -# GenType - 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/manual/latest/gentype-introduction.mdx b/pages/docs/manual/latest/gentype-introduction.mdx index 2aedbd3ef..8ccf57f51 100644 --- a/pages/docs/manual/latest/gentype-introduction.mdx +++ b/pages/docs/manual/latest/gentype-introduction.mdx @@ -4,19 +4,16 @@ description: "GenType - Interoperability between ReScript and TypeScript" canonical: "/docs/manual/latest/gentype-introduction" --- -# GenType +# ReScript & TypeScript -`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. +The ReScript compiler includes 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. It is called `genType`. 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 }`. +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"; _0: number } | { TAG: "B"; _0: string };`. ## A Quick Example @@ -34,7 +31,7 @@ First we'll set up a rescript-react component: @genType type color = | Red - | Blue; + | Blue @genType @react.component @@ -43,10 +40,10 @@ let make = (~name: string, ~color: color) => { switch (color) { | Red => "red" | Blue => "blue" - }; + } -
{React.string(name)}
; -}; +
{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: @@ -54,33 +51,29 @@ On a successful compile, `genType` will convert `src/MyComp.res` to a TS file ca ```ts // src/MyComp.gen.tsx -/* TypeScript file generated from MyComp.res by genType. */ -/* eslint-disable import/first */ - +/* TypeScript file generated from Main.res by genType. */ -import * as React from 'react'; +/* eslint-disable */ +/* tslint:disable */ -const $$toRE818596289: { [key: string]: any } = {"Red": 0, "Blue": 1}; +import * as React from "react"; -// tslint:disable-next-line:no-var-requires -const MyCompBS = require('./MyComp.bs'); +import * as MainBS__Es6Import from "./Main.res"; +const MainBS: any = MainBS__Es6Import; -// 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 -}; +export const make: React.ComponentType<{ + readonly color: color; + readonly name: string; +}> = MainBS.make; ``` 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! +Therefore 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: @@ -89,10 +82,12 @@ Within our TypeScript application, we can now import and use the React component import { make as MyComp } from "./MyComp.gen.tsx"; const App = () => { - return (
-

My Component

- -
); + return ( +
+

My Component

+ +
+ ); }; ``` @@ -100,6 +95,100 @@ That's it for our quick example. For detailed information, head to the [Getting Started](/docs/manual/latest/gentype-getting-started) or [Usage](/docs/manual/latest/gentype-usage) section. -## Development +## 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): + +```json +"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: + +```json + //... + "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. -Since ReScript v10.1, genType is part of the compiler's [GitHub repository](https://github.com/rescript-lang/rescript-compiler). +- **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"`. From ad799e6ce6c5cc64b9f2f779c5774230f150774f Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Tue, 5 Dec 2023 11:44:07 +0100 Subject: [PATCH 03/11] TypeScript interop structure --- pages/docs/manual/latest/bind-to-ts-object.mdx | 7 +++++++ pages/docs/manual/latest/bind-to-ts-primitive.mdx | 7 +++++++ pages/docs/manual/latest/bind-to-ts-variant.mdx | 7 +++++++ 3 files changed, 21 insertions(+) create mode 100644 pages/docs/manual/latest/bind-to-ts-object.mdx create mode 100644 pages/docs/manual/latest/bind-to-ts-primitive.mdx create mode 100644 pages/docs/manual/latest/bind-to-ts-variant.mdx diff --git a/pages/docs/manual/latest/bind-to-ts-object.mdx b/pages/docs/manual/latest/bind-to-ts-object.mdx new file mode 100644 index 000000000..3ac95ffcf --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-object.mdx @@ -0,0 +1,7 @@ +--- +title: "Bind to TS Object" +description: "Interop with TS objects in ReScript" +canonical: "/docs/manual/latest/bind-to-ts-object" +--- + +# Bind to TS Object diff --git a/pages/docs/manual/latest/bind-to-ts-primitive.mdx b/pages/docs/manual/latest/bind-to-ts-primitive.mdx new file mode 100644 index 000000000..ba97f3437 --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-primitive.mdx @@ -0,0 +1,7 @@ +--- +title: "Bind to TS primitive values" +description: "Interop with TS primitives in ReScript" +canonical: "/docs/manual/latest/bind-to-ts-primitive" +--- + +# Bind to TS Primitives diff --git a/pages/docs/manual/latest/bind-to-ts-variant.mdx b/pages/docs/manual/latest/bind-to-ts-variant.mdx new file mode 100644 index 000000000..5effad3b3 --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-variant.mdx @@ -0,0 +1,7 @@ +--- +title: "Bind variants to TS" +description: "Interop with ReScript variants in TypeScript" +canonical: "/docs/manual/latest/bind-to-ts-variant" +--- + +# Bind to TS Object From 28e38466d7acee7c7e52e3711471d205ddaf11df Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Tue, 5 Dec 2023 12:36:15 +0100 Subject: [PATCH 04/11] Update gentype intro --- data/sidebar_manual_latest.json | 6 ++++-- next.config.mjs | 6 +++--- pages/docs/manual/latest/gentype-introduction.mdx | 15 +-------------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index 64140a108..64853d01f 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -55,9 +55,11 @@ ], "TypeScript Interop": [ "gentype-introduction", - "gentype-getting-started", "gentype-usage", - "gentype-supported-types" + "gentype-supported-types", + "bind-to-ts-object", + "bind-to-ts-primitive", + "bind-to-ts-variant" ], "Build System": [ "build-overview", diff --git a/next.config.mjs b/next.config.mjs index 804fb6c90..07e180be9 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -109,17 +109,17 @@ const config = { }, { source: "/docs/gentype/latest/getting-started", - destination: "/docs/manual/latest/gentype-getting-started", + destination: "/docs/manual/latest/gentype-introduction", permanent: true, }, { source: "/docs/gentype/latest/usage", - destination: "/docs/manual/latest/gentype-usage", + destination: "/docs/manual/latest/gentype-introduction", permanent: true, }, { source: "/docs/gentype/latest/supported-types", - destination: "/docs/manual/latest/gentype-supported-types", + destination: "/docs/manual/latest/gentype-introduction", permanent: true, }, ]; diff --git a/pages/docs/manual/latest/gentype-introduction.mdx b/pages/docs/manual/latest/gentype-introduction.mdx index 8ccf57f51..3f7165a6d 100644 --- a/pages/docs/manual/latest/gentype-introduction.mdx +++ b/pages/docs/manual/latest/gentype-introduction.mdx @@ -91,21 +91,8 @@ const App = () => { }; ``` -That's it for our quick example. - -For detailed information, head to the [Getting Started](/docs/manual/latest/gentype-getting-started) or [Usage](/docs/manual/latest/gentype-usage) section. - ## 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): ```json @@ -189,6 +176,6 @@ These features are for experimentation only. They could be changed/removed any t ## 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. +- **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"`. From 339f77aa8bd55b32c6d8602f0f7593d566932d0e Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Tue, 5 Dec 2023 13:14:10 +0100 Subject: [PATCH 05/11] Split up supported types to multiple bind-to-ts files --- data/sidebar_manual_latest.json | 9 +- .../manual/latest/bind-to-ts-collections.mdx | 20 ++ .../manual/latest/bind-to-ts-function.mdx | 24 +++ .../docs/manual/latest/bind-to-ts-object.mdx | 19 ++ .../manual/latest/bind-to-ts-option-null.mdx | 18 ++ pages/docs/manual/latest/bind-to-ts-other.mdx | 86 ++++++++ .../manual/latest/bind-to-ts-primitive.mdx | 12 ++ .../docs/manual/latest/bind-to-ts-variant.mdx | 30 ++- .../manual/latest/gentype-supported-types.mdx | 195 ------------------ 9 files changed, 214 insertions(+), 199 deletions(-) create mode 100644 pages/docs/manual/latest/bind-to-ts-collections.mdx create mode 100644 pages/docs/manual/latest/bind-to-ts-function.mdx create mode 100644 pages/docs/manual/latest/bind-to-ts-option-null.mdx create mode 100644 pages/docs/manual/latest/bind-to-ts-other.mdx delete mode 100644 pages/docs/manual/latest/gentype-supported-types.mdx diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index 64853d01f..67bd90667 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -56,10 +56,13 @@ "TypeScript Interop": [ "gentype-introduction", "gentype-usage", - "gentype-supported-types", - "bind-to-ts-object", "bind-to-ts-primitive", - "bind-to-ts-variant" + "bind-to-ts-collections", + "bind-to-ts-object", + "bind-to-ts-option-null", + "bind-to-ts-function", + "bind-to-ts-variant", + "bind-to-ts-other" ], "Build System": [ "build-overview", diff --git a/pages/docs/manual/latest/bind-to-ts-collections.mdx b/pages/docs/manual/latest/bind-to-ts-collections.mdx new file mode 100644 index 000000000..1793fbf32 --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-collections.mdx @@ -0,0 +1,20 @@ +--- +title: "Bind collections to TS" +description: "Interop with collection types between ReScript and TypeScript" +canonical: "/docs/manual/latest/bind-to-ts-collections" +--- + +# Bind collections to TS + +## 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, so they're currenty exported to mutable tuples. + +## 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. As opposed to TS, `ImmutableArray.t` does not allow casting in either direction with normal arrays. Instead, a copy must be performed using `fromArray` and `toArray`. diff --git a/pages/docs/manual/latest/bind-to-ts-function.mdx b/pages/docs/manual/latest/bind-to-ts-function.mdx new file mode 100644 index 000000000..664a9792f --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-function.mdx @@ -0,0 +1,24 @@ +--- +title: "Bind to TS Function" +description: "Interop with functions between ReScript and TypeScript" +canonical: "/docs/manual/latest/bind-to-ts-function" +--- + +# Bind to TS Function + +## 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); +``` diff --git a/pages/docs/manual/latest/bind-to-ts-object.mdx b/pages/docs/manual/latest/bind-to-ts-object.mdx index 3ac95ffcf..227383dcd 100644 --- a/pages/docs/manual/latest/bind-to-ts-object.mdx +++ b/pages/docs/manual/latest/bind-to-ts-object.mdx @@ -5,3 +5,22 @@ canonical: "/docs/manual/latest/bind-to-ts-object" --- # Bind to TS Object + +## 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 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 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. diff --git a/pages/docs/manual/latest/bind-to-ts-option-null.mdx b/pages/docs/manual/latest/bind-to-ts-option-null.mdx new file mode 100644 index 000000000..bf27a3699 --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-option-null.mdx @@ -0,0 +1,18 @@ +--- +title: "Bind to optional or nullable TS types" +description: "Interop with ReScript option and nullable in TypeScript" +canonical: "/docs/manual/latest/bind-to-ts-option-null" +--- + +# Bind ReScript option and nullable to TS + +## 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. `Js.Nullable.t`, such as `Js.Nullable.null`, `Js.Nullable.undefined`, `Js.Nullable.return(0)`, `Js.Nullable.return(1)`, `Js.Nullable.return(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. diff --git a/pages/docs/manual/latest/bind-to-ts-other.mdx b/pages/docs/manual/latest/bind-to-ts-other.mdx new file mode 100644 index 000000000..a05d0d297 --- /dev/null +++ b/pages/docs/manual/latest/bind-to-ts-other.mdx @@ -0,0 +1,86 @@ +--- +title: "More TypeScript interop" +description: "More TypeScript interop" +canonical: "/docs/manual/latest/bind-to-ts-other" +--- + +# More TypeScript interop + +## Imported Types + +It's possible to import an existing TS 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 `Js.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/manual/latest/bind-to-ts-primitive.mdx b/pages/docs/manual/latest/bind-to-ts-primitive.mdx index ba97f3437..0bb19b279 100644 --- a/pages/docs/manual/latest/bind-to-ts-primitive.mdx +++ b/pages/docs/manual/latest/bind-to-ts-primitive.mdx @@ -5,3 +5,15 @@ canonical: "/docs/manual/latest/bind-to-ts-primitive" --- # Bind to TS Primitives + +## 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`. diff --git a/pages/docs/manual/latest/bind-to-ts-variant.mdx b/pages/docs/manual/latest/bind-to-ts-variant.mdx index 5effad3b3..d750ed5e2 100644 --- a/pages/docs/manual/latest/bind-to-ts-variant.mdx +++ b/pages/docs/manual/latest/bind-to-ts-variant.mdx @@ -4,4 +4,32 @@ description: "Interop with ReScript variants in TypeScript" canonical: "/docs/manual/latest/bind-to-ts-variant" --- -# Bind to TS Object +# Bind ReScript variants to TS + +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. diff --git a/pages/docs/manual/latest/gentype-supported-types.mdx b/pages/docs/manual/latest/gentype-supported-types.mdx deleted file mode 100644 index 39a3795a6..000000000 --- a/pages/docs/manual/latest/gentype-supported-types.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: "Supported Types" -description: "Supported types and value conversion in GenType" -canonical: "/docs/manual/latest/gentype-supported-types" ---- - -# GenType - 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 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 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, 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. As opposed to TS, `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 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 => ...)`. From c4a61052ae3efa2016d68b6228166ad00cde721d Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Thu, 28 Dec 2023 00:42:28 +0900 Subject: [PATCH 06/11] TypeScript section into JavaScript interop Co-authored-by: Florian Hammerschmidt --- data/sidebar_manual_latest.json | 14 +- .../manual/latest/bind-to-ts-collections.mdx | 20 -- .../manual/latest/bind-to-ts-function.mdx | 24 --- .../docs/manual/latest/bind-to-ts-object.mdx | 26 --- .../manual/latest/bind-to-ts-option-null.mdx | 18 -- pages/docs/manual/latest/bind-to-ts-other.mdx | 86 -------- .../manual/latest/bind-to-ts-primitive.mdx | 19 -- .../docs/manual/latest/bind-to-ts-variant.mdx | 35 ---- .../manual/latest/build-configuration.mdx | 35 ++++ .../manual/latest/gentype-introduction.mdx | 181 ---------------- pages/docs/manual/latest/gentype-usage.mdx | 189 ----------------- .../manual/latest/typescript-integration.mdx | 196 ++++++++++++++++++ 12 files changed, 233 insertions(+), 610 deletions(-) delete mode 100644 pages/docs/manual/latest/bind-to-ts-collections.mdx delete mode 100644 pages/docs/manual/latest/bind-to-ts-function.mdx delete mode 100644 pages/docs/manual/latest/bind-to-ts-object.mdx delete mode 100644 pages/docs/manual/latest/bind-to-ts-option-null.mdx delete mode 100644 pages/docs/manual/latest/bind-to-ts-other.mdx delete mode 100644 pages/docs/manual/latest/bind-to-ts-primitive.mdx delete mode 100644 pages/docs/manual/latest/bind-to-ts-variant.mdx delete mode 100644 pages/docs/manual/latest/gentype-introduction.mdx delete mode 100644 pages/docs/manual/latest/gentype-usage.mdx create mode 100644 pages/docs/manual/latest/typescript-integration.mdx diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index 67bd90667..43a78c47a 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -51,18 +51,8 @@ "use-illegal-identifier-names", "generate-converters-accessors", "browser-support-polyfills", - "libraries" - ], - "TypeScript Interop": [ - "gentype-introduction", - "gentype-usage", - "bind-to-ts-primitive", - "bind-to-ts-collections", - "bind-to-ts-object", - "bind-to-ts-option-null", - "bind-to-ts-function", - "bind-to-ts-variant", - "bind-to-ts-other" + "libraries", + "typescript-integration" ], "Build System": [ "build-overview", diff --git a/pages/docs/manual/latest/bind-to-ts-collections.mdx b/pages/docs/manual/latest/bind-to-ts-collections.mdx deleted file mode 100644 index 1793fbf32..000000000 --- a/pages/docs/manual/latest/bind-to-ts-collections.mdx +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: "Bind collections to TS" -description: "Interop with collection types between ReScript and TypeScript" -canonical: "/docs/manual/latest/bind-to-ts-collections" ---- - -# Bind collections to TS - -## 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, so they're currenty exported to mutable tuples. - -## 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. As opposed to TS, `ImmutableArray.t` does not allow casting in either direction with normal arrays. Instead, a copy must be performed using `fromArray` and `toArray`. diff --git a/pages/docs/manual/latest/bind-to-ts-function.mdx b/pages/docs/manual/latest/bind-to-ts-function.mdx deleted file mode 100644 index 664a9792f..000000000 --- a/pages/docs/manual/latest/bind-to-ts-function.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: "Bind to TS Function" -description: "Interop with functions between ReScript and TypeScript" -canonical: "/docs/manual/latest/bind-to-ts-function" ---- - -# Bind to TS Function - -## 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); -``` diff --git a/pages/docs/manual/latest/bind-to-ts-object.mdx b/pages/docs/manual/latest/bind-to-ts-object.mdx deleted file mode 100644 index 227383dcd..000000000 --- a/pages/docs/manual/latest/bind-to-ts-object.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Bind to TS Object" -description: "Interop with TS objects in ReScript" -canonical: "/docs/manual/latest/bind-to-ts-object" ---- - -# Bind to TS Object - -## 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 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 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. diff --git a/pages/docs/manual/latest/bind-to-ts-option-null.mdx b/pages/docs/manual/latest/bind-to-ts-option-null.mdx deleted file mode 100644 index bf27a3699..000000000 --- a/pages/docs/manual/latest/bind-to-ts-option-null.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Bind to optional or nullable TS types" -description: "Interop with ReScript option and nullable in TypeScript" -canonical: "/docs/manual/latest/bind-to-ts-option-null" ---- - -# Bind ReScript option and nullable to TS - -## 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. `Js.Nullable.t`, such as `Js.Nullable.null`, `Js.Nullable.undefined`, `Js.Nullable.return(0)`, `Js.Nullable.return(1)`, `Js.Nullable.return(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. diff --git a/pages/docs/manual/latest/bind-to-ts-other.mdx b/pages/docs/manual/latest/bind-to-ts-other.mdx deleted file mode 100644 index a05d0d297..000000000 --- a/pages/docs/manual/latest/bind-to-ts-other.mdx +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: "More TypeScript interop" -description: "More TypeScript interop" -canonical: "/docs/manual/latest/bind-to-ts-other" ---- - -# More TypeScript interop - -## Imported Types - -It's possible to import an existing TS 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 `Js.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/manual/latest/bind-to-ts-primitive.mdx b/pages/docs/manual/latest/bind-to-ts-primitive.mdx deleted file mode 100644 index 0bb19b279..000000000 --- a/pages/docs/manual/latest/bind-to-ts-primitive.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "Bind to TS primitive values" -description: "Interop with TS primitives in ReScript" -canonical: "/docs/manual/latest/bind-to-ts-primitive" ---- - -# Bind to TS Primitives - -## 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`. diff --git a/pages/docs/manual/latest/bind-to-ts-variant.mdx b/pages/docs/manual/latest/bind-to-ts-variant.mdx deleted file mode 100644 index d750ed5e2..000000000 --- a/pages/docs/manual/latest/bind-to-ts-variant.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: "Bind variants to TS" -description: "Interop with ReScript variants in TypeScript" -canonical: "/docs/manual/latest/bind-to-ts-variant" ---- - -# Bind ReScript variants to TS - -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. diff --git a/pages/docs/manual/latest/build-configuration.mdx b/pages/docs/manual/latest/build-configuration.mdx index 485753177..3e2e3c474 100644 --- a/pages/docs/manual/latest/build-configuration.mdx +++ b/pages/docs/manual/latest/build-configuration.mdx @@ -192,6 +192,41 @@ 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/gentype-introduction.mdx b/pages/docs/manual/latest/gentype-introduction.mdx deleted file mode 100644 index 3f7165a6d..000000000 --- a/pages/docs/manual/latest/gentype-introduction.mdx +++ /dev/null @@ -1,181 +0,0 @@ ---- -title: "Introduction" -description: "GenType - Interoperability between ReScript and TypeScript" -canonical: "/docs/manual/latest/gentype-introduction" ---- - -# ReScript & TypeScript - -The ReScript compiler includes 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. It is called `genType`. - -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. - -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"; _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-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 Main.res by genType. */ - -/* eslint-disable */ -/* tslint:disable */ - -import * as React from "react"; - -import * as MainBS__Es6Import from "./Main.res"; -const MainBS: any = MainBS__Es6Import; - -export type color = "Red" | "Blue"; - -export type Props = { readonly color: color; readonly name: string }; - -export const make: React.ComponentType<{ - readonly color: color; - readonly name: string; -}> = MainBS.make; -``` - -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 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

- -
- ); -}; -``` - -## Setup - -Add a `gentypeconfig` section to your `rescript.json` (See [Configuration](#configuration) for details): - -```json -"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: - -```json - //... - "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 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/latest/gentype-usage.mdx b/pages/docs/manual/latest/gentype-usage.mdx deleted file mode 100644 index 36b114634..000000000 --- a/pages/docs/manual/latest/gentype-usage.mdx +++ /dev/null @@ -1,189 +0,0 @@ ---- -title: "Usage" -description: "GenType - Interoperability between ReScript and TypeScript" -canonical: "/docs/manual/latest/gentype-usage" ---- - -# 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 = _ => 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/typescript-integration.mdx b/pages/docs/manual/latest/typescript-integration.mdx new file mode 100644 index 000000000..40adcf0bf --- /dev/null +++ b/pages/docs/manual/latest/typescript-integration.mdx @@ -0,0 +1,196 @@ +--- +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 TypeScript function. + +We want to be able to import the function like any other 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!"); +``` + +## 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` in the project `tsconfig.json`: + +```json +{ + "compilerOptions": { + "allowJs": true + } +} +``` + +### TypeScript Module Resolutions + +Make sure to set the same `moduleResolution` in the both `rescript.json` and `tsconfig.json` so that the output of genType is performed at 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 uses `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"`. From 67574642f25b323da5d3caa58478a434db1b414c Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Fri, 29 Dec 2023 00:07:27 +0100 Subject: [PATCH 07/11] Fix links --- misc_docs/syntax/decorator_gentype.mdx | 4 ++-- next.config.mjs | 8 ++++---- pages/docs/manual/latest/build-configuration.mdx | 2 +- pages/docs/manual/latest/typescript-integration.mdx | 10 ++++++---- src/DocsOverview.res | 2 +- src/common/Constants.res | 2 +- src/components/Navigation.res | 2 +- src/layouts/LandingPageLayout.res | 2 +- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/misc_docs/syntax/decorator_gentype.mdx b/misc_docs/syntax/decorator_gentype.mdx index 52f976187..e585c5eec 100644 --- a/misc_docs/syntax/decorator_gentype.mdx +++ b/misc_docs/syntax/decorator_gentype.mdx @@ -8,7 +8,7 @@ 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, or plain JavaScript codebases, without losing type information across different type systems. -[GenType](/docs/manual/latest/gentype-introduction) 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. +[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 @@ -61,4 +61,4 @@ export const make: React.ComponentType<{ ### References -* [GenType](/docs/manual/latest/gentype-introduction) +* [TypeScript Integration](/docs/manual/latest/typescript-integration) diff --git a/next.config.mjs b/next.config.mjs index 07e180be9..bb2f92f7e 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -104,22 +104,22 @@ const config = { }, { source: "/docs/gentype/latest/introduction", - destination: "/docs/manual/latest/gentype-introduction", + destination: "/docs/manual/latest/typescript-integration", permanent: true, }, { source: "/docs/gentype/latest/getting-started", - destination: "/docs/manual/latest/gentype-introduction", + destination: "/docs/manual/latest/typescript-integration", permanent: true, }, { source: "/docs/gentype/latest/usage", - destination: "/docs/manual/latest/gentype-introduction", + destination: "/docs/manual/latest/typescript-integration", permanent: true, }, { source: "/docs/gentype/latest/supported-types", - destination: "/docs/manual/latest/gentype-introduction", + destination: "/docs/manual/latest/typescript-integration", permanent: true, }, ]; diff --git a/pages/docs/manual/latest/build-configuration.mdx b/pages/docs/manual/latest/build-configuration.mdx index 3e2e3c474..1588948a7 100644 --- a/pages/docs/manual/latest/build-configuration.mdx +++ b/pages/docs/manual/latest/build-configuration.mdx @@ -149,7 +149,6 @@ one of the following: - `".res.js"` - `".res.mjs"` - `".res.cjs"` - <<<<<<< HEAD ### Design Decisions @@ -215,6 +214,7 @@ To enable genType, set `"gentypeconfig"` at top level in the project's `rescript `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` diff --git a/pages/docs/manual/latest/typescript-integration.mdx b/pages/docs/manual/latest/typescript-integration.mdx index 40adcf0bf..ea0c16b6b 100644 --- a/pages/docs/manual/latest/typescript-integration.mdx +++ b/pages/docs/manual/latest/typescript-integration.mdx @@ -25,9 +25,9 @@ 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 TypeScript function. +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 in our existing TypeScript code, but we also want to preserve all the ReScript types in the TypeScript type system +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!** @@ -64,11 +64,13 @@ On a successful compile, `genType` will convert `src/Color.res` to a TypeScript /* eslint-disable */ /* tslint:disable */ -import * as ColorJS from './Color.res.js'; +import * as ColorJS from "./Color.res.js"; export type color = "Red" | "Blue"; -export const printColorMessage: (color:color) => void = ColorJS.printColorMessage as any; +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"`. diff --git a/src/DocsOverview.res b/src/DocsOverview.res index 2e6f47825..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/manual/latest/gentype-introduction"), + ("GenType", "/docs/manual/latest/typescript-integration"), ("Reanalyze", "https://github.com/reason-association/reanalyze"), ] diff --git a/src/common/Constants.res b/src/common/Constants.res index c6bc22cd0..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/manual/latest/gentype-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 4299ba3e5..fe078cc85 100644 --- a/src/components/Navigation.res +++ b/src/components/Navigation.res @@ -190,7 +190,7 @@ module DocsSection = { imgSrc: "/static/ic_gentype@2x.png", title: "GenType", description: "Seamless TypeScript integration", - href: "/docs/manual/latest/gentype-introduction", + href: "/docs/manual/latest/typescript-integration", isActive: url => { switch url.fullpath { | ["docs", "manual", _, fragment] => fragment->Js.String2.startsWith("gentype") diff --git a/src/layouts/LandingPageLayout.res b/src/layouts/LandingPageLayout.res index ad9c1c721..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/manual/latest/gentype-introduction", + href: "/docs/manual/latest/typescript-integration", }, ] From 4293fcb8c7028ab371c3f5038dd0c315eeddc51a Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Fri, 29 Dec 2023 00:11:34 +0100 Subject: [PATCH 08/11] Minor text fixes --- pages/docs/manual/latest/typescript-integration.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/docs/manual/latest/typescript-integration.mdx b/pages/docs/manual/latest/typescript-integration.mdx index ea0c16b6b..a0133fbfc 100644 --- a/pages/docs/manual/latest/typescript-integration.mdx +++ b/pages/docs/manual/latest/typescript-integration.mdx @@ -103,7 +103,7 @@ The minimal configuration of genType is following: } ``` -And don't forget to make sure `allowJs` in the project `tsconfig.json`: +And don't forget to make sure `allowJs` is set to `true` in the project's `tsconfig.json`: ```json { @@ -115,7 +115,7 @@ And don't forget to make sure `allowJs` in the project `tsconfig.json`: ### TypeScript Module Resolutions -Make sure to set the same `moduleResolution` in the both `rescript.json` and `tsconfig.json` so that the output of genType is performed at preferred module resolution. +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: @@ -139,7 +139,7 @@ Then `moduleResolution` in `gentypeconfig` should be same value: } ``` -In case of the TypeScript project uses `Bundler` module resolution, `allowImportingTsExtensions` should also be `true`: +In case of the TypeScript project using `Bundler` module resolution, `allowImportingTsExtensions` should also be `true`: ```json // tsconfig.json From fdf365e0951301388a521628a3e8eaf18a4ea385 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Fri, 29 Dec 2023 00:29:22 +0100 Subject: [PATCH 09/11] Add example of whole module @genType annotation --- .../manual/latest/typescript-integration.mdx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pages/docs/manual/latest/typescript-integration.mdx b/pages/docs/manual/latest/typescript-integration.mdx index a0133fbfc..7b8f8967f 100644 --- a/pages/docs/manual/latest/typescript-integration.mdx +++ b/pages/docs/manual/latest/typescript-integration.mdx @@ -85,6 +85,42 @@ 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). From 0d24d05d81cb7168e8cc6f7fe3acaaff6360e3d5 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Fri, 29 Dec 2023 00:34:34 +0100 Subject: [PATCH 10/11] Fix more links --- pages/docs/manual/v10.0.0/build-configuration.mdx | 15 ++++++++------- pages/docs/manual/v9.0.0/build-configuration.mdx | 11 ++++++----- pages/docs/react/latest/introduction.mdx | 2 +- pages/docs/react/v0.10.0/introduction.mdx | 2 +- pages/docs/react/v0.11.0/introduction.mdx | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pages/docs/manual/v10.0.0/build-configuration.mdx b/pages/docs/manual/v10.0.0/build-configuration.mdx index c1f1e5d9d..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/manual/latest/gentype-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 3cf1ab936..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/manual/latest/gentype-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 610ab1c83..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/manual/latest/gentype-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 c3f3c1057..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/manual/latest/gentype-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.** > diff --git a/pages/docs/react/v0.11.0/introduction.mdx b/pages/docs/react/v0.11.0/introduction.mdx index 9e4eff3f7..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/manual/latest/gentype-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.** > From aae07eb1b5e7507dbc97f181c8673537839b7810 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Fri, 29 Dec 2023 00:40:26 +0100 Subject: [PATCH 11/11] Fix isActive for TS chapter --- src/components/Navigation.res | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Navigation.res b/src/components/Navigation.res index fe078cc85..fe4bfb4aa 100644 --- a/src/components/Navigation.res +++ b/src/components/Navigation.res @@ -169,7 +169,7 @@ module DocsSection = { href: `/docs/manual/${version}/introduction`, isActive: url => { switch url.fullpath { - | ["docs", "manual", _, fragment] => !(fragment->Js.String2.startsWith("gentype")) + | ["docs", "manual", _, fragment] => fragment !== "typescript-integration" | _ => false } }, @@ -193,7 +193,7 @@ module DocsSection = { href: "/docs/manual/latest/typescript-integration", isActive: url => { switch url.fullpath { - | ["docs", "manual", _, fragment] => fragment->Js.String2.startsWith("gentype") + | ["docs", "manual", _, "typescript-integration"] => true | _ => false } },