53 files changed,
+29779,
-0
+62,
-0
1@@ -0,0 +1,62 @@
2+{
3+ "version": 3,
4+ "skills": {
5+ "frontend-design": {
6+ "source": "anthropics/skills",
7+ "sourceType": "github",
8+ "sourceUrl": "https://github.com/anthropics/skills.git",
9+ "skillPath": "skills/frontend-design/SKILL.md",
10+ "skillFolderHash": "928950704df8a8b885c03de5da626331e6f29cf8",
11+ "installedAt": "2026-02-24T11:37:28.780Z",
12+ "updatedAt": "2026-02-24T11:37:28.780Z"
13+ },
14+ "working-with-jj": {
15+ "source": "ypares/agent-skills",
16+ "sourceType": "github",
17+ "sourceUrl": "https://github.com/ypares/agent-skills.git",
18+ "skillPath": "working-with-jj/SKILL.md",
19+ "skillFolderHash": "f1b7b2ce97480075661d73a81a14df3002562c1c",
20+ "installedAt": "2026-02-24T11:40:02.311Z",
21+ "updatedAt": "2026-02-24T11:40:18.583Z"
22+ },
23+ "tailwind-css-patterns": {
24+ "source": "giuseppe-trisciuoglio/developer-kit",
25+ "sourceType": "github",
26+ "sourceUrl": "https://github.com/giuseppe-trisciuoglio/developer-kit.git",
27+ "skillPath": "plugins/developer-kit-typescript/skills/tailwind-css-patterns/SKILL.md",
28+ "skillFolderHash": "0e30d1ada901fd9207bb1cfde1c4202b99125607",
29+ "installedAt": "2026-02-24T11:44:10.933Z",
30+ "updatedAt": "2026-02-24T11:44:10.933Z"
31+ },
32+ "writing-clearly-and-concisely": {
33+ "source": "obra/the-elements-of-style",
34+ "sourceType": "github",
35+ "sourceUrl": "https://github.com/obra/the-elements-of-style.git",
36+ "skillPath": "skills/writing-clearly-and-concisely/SKILL.md",
37+ "skillFolderHash": "9f8fda5492c471811dedcdecda6701ef63f6df9b",
38+ "installedAt": "2026-02-24T12:25:00.077Z",
39+ "updatedAt": "2026-02-24T12:25:00.077Z"
40+ },
41+ "web-design-guidelines": {
42+ "source": "vercel-labs/agent-skills",
43+ "sourceType": "github",
44+ "sourceUrl": "https://github.com/vercel-labs/agent-skills.git",
45+ "skillPath": "skills/web-design-guidelines/SKILL.md",
46+ "skillFolderHash": "3116f3e62dbd02b44a598b1aa690d2a8938e8f89",
47+ "installedAt": "2026-02-24T12:25:57.916Z",
48+ "updatedAt": "2026-02-24T12:25:57.916Z"
49+ },
50+ "playwright-cli": {
51+ "source": "microsoft/playwright-cli",
52+ "sourceType": "github",
53+ "sourceUrl": "https://github.com/microsoft/playwright-cli.git",
54+ "skillPath": "skills/playwright-cli/SKILL.md",
55+ "skillFolderHash": "a5a8823e403adc13b2488aae9968d6d92adbd2d7",
56+ "installedAt": "2026-02-25T02:16:13.361Z",
57+ "updatedAt": "2026-02-25T02:16:13.361Z"
58+ }
59+ },
60+ "dismissed": {
61+ "findSkillsPrompt": true
62+ }
63+}
+64,
-0
1@@ -0,0 +1,64 @@
2+{
3+ "$schema": "https://opencode.ai/config.json",
4+ "autoupdate": false,
5+ "default_agent": "plan",
6+ "share": "disabled",
7+ "agent": {
8+ "plan": {
9+ "mode": "primary",
10+ "model": "opencode-go/kimi-k2.5"
11+ },
12+ "build": {
13+ "mode": "primary",
14+ "model": "opencode-go/kimi-k2.5"
15+ }
16+ },
17+ "permission": {
18+ "*": "allow",
19+ "bash": {
20+ "*": "allow",
21+ "go *": "allow",
22+ "go get *": "ask",
23+ "git *": "ask",
24+ "pnpm add *": "ask",
25+ "npm *": "deny",
26+ "npx *": "deny",
27+ "rm *": "ask",
28+ "rm /tmp/**/*": "allow",
29+ "rm -rf /tmp/**/*": "allow",
30+ "pnpm run *": "allow",
31+ "echo *": "allow",
32+ "pnpm format": "allow",
33+ "pnpm check": "allow",
34+ "pnpm build": "allow"
35+ },
36+ "external_directory": "ask",
37+ "doom_loop": "ask",
38+ "read": {
39+ "*": "allow",
40+ "*.env": "deny",
41+ "*.env.*": "deny",
42+ "*.env.example": "allow",
43+ "~/.agents/**/*": "allow"
44+ },
45+ "write": {
46+ "/tmp/**/*": "allow",
47+ "/tmp/**/.*": "allow"
48+ }
49+ },
50+ "mcp": {
51+ "exa": {
52+ "type": "remote",
53+ "url": "https://mcp.exa.ai/mcp?tools=web_search_exa,get_code_context_exa",
54+ "enabled": true
55+ },
56+ "context7": {
57+ "type": "remote",
58+ "url": "https://mcp.context7.com/mcp",
59+ "headers": {
60+ "CONTEXT7_API_KEY": "ctx7sk-cd88ebbc-3fd3-40d2-a0fc-ba66e634f420"
61+ },
62+ "enabled": true
63+ }
64+ }
65+}
+177,
-0
1@@ -0,0 +1,177 @@
2+
3+ Apache License
4+ Version 2.0, January 2004
5+ http://www.apache.org/licenses/
6+
7+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8+
9+ 1. Definitions.
10+
11+ "License" shall mean the terms and conditions for use, reproduction,
12+ and distribution as defined by Sections 1 through 9 of this document.
13+
14+ "Licensor" shall mean the copyright owner or entity authorized by
15+ the copyright owner that is granting the License.
16+
17+ "Legal Entity" shall mean the union of the acting entity and all
18+ other entities that control, are controlled by, or are under common
19+ control with that entity. For the purposes of this definition,
20+ "control" means (i) the power, direct or indirect, to cause the
21+ direction or management of such entity, whether by contract or
22+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
23+ outstanding shares, or (iii) beneficial ownership of such entity.
24+
25+ "You" (or "Your") shall mean an individual or Legal Entity
26+ exercising permissions granted by this License.
27+
28+ "Source" form shall mean the preferred form for making modifications,
29+ including but not limited to software source code, documentation
30+ source, and configuration files.
31+
32+ "Object" form shall mean any form resulting from mechanical
33+ transformation or translation of a Source form, including but
34+ not limited to compiled object code, generated documentation,
35+ and conversions to other media types.
36+
37+ "Work" shall mean the work of authorship, whether in Source or
38+ Object form, made available under the License, as indicated by a
39+ copyright notice that is included in or attached to the work
40+ (an example is provided in the Appendix below).
41+
42+ "Derivative Works" shall mean any work, whether in Source or Object
43+ form, that is based on (or derived from) the Work and for which the
44+ editorial revisions, annotations, elaborations, or other modifications
45+ represent, as a whole, an original work of authorship. For the purposes
46+ of this License, Derivative Works shall not include works that remain
47+ separable from, or merely link (or bind by name) to the interfaces of,
48+ the Work and Derivative Works thereof.
49+
50+ "Contribution" shall mean any work of authorship, including
51+ the original version of the Work and any modifications or additions
52+ to that Work or Derivative Works thereof, that is intentionally
53+ submitted to Licensor for inclusion in the Work by the copyright owner
54+ or by an individual or Legal Entity authorized to submit on behalf of
55+ the copyright owner. For the purposes of this definition, "submitted"
56+ means any form of electronic, verbal, or written communication sent
57+ to the Licensor or its representatives, including but not limited to
58+ communication on electronic mailing lists, source code control systems,
59+ and issue tracking systems that are managed by, or on behalf of, the
60+ Licensor for the purpose of discussing and improving the Work, but
61+ excluding communication that is conspicuously marked or otherwise
62+ designated in writing by the copyright owner as "Not a Contribution."
63+
64+ "Contributor" shall mean Licensor and any individual or Legal Entity
65+ on behalf of whom a Contribution has been received by Licensor and
66+ subsequently incorporated within the Work.
67+
68+ 2. Grant of Copyright License. Subject to the terms and conditions of
69+ this License, each Contributor hereby grants to You a perpetual,
70+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71+ copyright license to reproduce, prepare Derivative Works of,
72+ publicly display, publicly perform, sublicense, and distribute the
73+ Work and such Derivative Works in Source or Object form.
74+
75+ 3. Grant of Patent License. Subject to the terms and conditions of
76+ this License, each Contributor hereby grants to You a perpetual,
77+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78+ (except as stated in this section) patent license to make, have made,
79+ use, offer to sell, sell, import, and otherwise transfer the Work,
80+ where such license applies only to those patent claims licensable
81+ by such Contributor that are necessarily infringed by their
82+ Contribution(s) alone or by combination of their Contribution(s)
83+ with the Work to which such Contribution(s) was submitted. If You
84+ institute patent litigation against any entity (including a
85+ cross-claim or counterclaim in a lawsuit) alleging that the Work
86+ or a Contribution incorporated within the Work constitutes direct
87+ or contributory patent infringement, then any patent licenses
88+ granted to You under this License for that Work shall terminate
89+ as of the date such litigation is filed.
90+
91+ 4. Redistribution. You may reproduce and distribute copies of the
92+ Work or Derivative Works thereof in any medium, with or without
93+ modifications, and in Source or Object form, provided that You
94+ meet the following conditions:
95+
96+ (a) You must give any other recipients of the Work or
97+ Derivative Works a copy of this License; and
98+
99+ (b) You must cause any modified files to carry prominent notices
100+ stating that You changed the files; and
101+
102+ (c) You must retain, in the Source form of any Derivative Works
103+ that You distribute, all copyright, patent, trademark, and
104+ attribution notices from the Source form of the Work,
105+ excluding those notices that do not pertain to any part of
106+ the Derivative Works; and
107+
108+ (d) If the Work includes a "NOTICE" text file as part of its
109+ distribution, then any Derivative Works that You distribute must
110+ include a readable copy of the attribution notices contained
111+ within such NOTICE file, excluding those notices that do not
112+ pertain to any part of the Derivative Works, in at least one
113+ of the following places: within a NOTICE text file distributed
114+ as part of the Derivative Works; within the Source form or
115+ documentation, if provided along with the Derivative Works; or,
116+ within a display generated by the Derivative Works, if and
117+ wherever such third-party notices normally appear. The contents
118+ of the NOTICE file are for informational purposes only and
119+ do not modify the License. You may add Your own attribution
120+ notices within Derivative Works that You distribute, alongside
121+ or as an addendum to the NOTICE text from the Work, provided
122+ that such additional attribution notices cannot be construed
123+ as modifying the License.
124+
125+ You may add Your own copyright statement to Your modifications and
126+ may provide additional or different license terms and conditions
127+ for use, reproduction, or distribution of Your modifications, or
128+ for any such Derivative Works as a whole, provided Your use,
129+ reproduction, and distribution of the Work otherwise complies with
130+ the conditions stated in this License.
131+
132+ 5. Submission of Contributions. Unless You explicitly state otherwise,
133+ any Contribution intentionally submitted for inclusion in the Work
134+ by You to the Licensor shall be under the terms and conditions of
135+ this License, without any additional terms or conditions.
136+ Notwithstanding the above, nothing herein shall supersede or modify
137+ the terms of any separate license agreement you may have executed
138+ with Licensor regarding such Contributions.
139+
140+ 6. Trademarks. This License does not grant permission to use the trade
141+ names, trademarks, service marks, or product names of the Licensor,
142+ except as required for reasonable and customary use in describing the
143+ origin of the Work and reproducing the content of the NOTICE file.
144+
145+ 7. Disclaimer of Warranty. Unless required by applicable law or
146+ agreed to in writing, Licensor provides the Work (and each
147+ Contributor provides its Contributions) on an "AS IS" BASIS,
148+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149+ implied, including, without limitation, any warranties or conditions
150+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151+ PARTICULAR PURPOSE. You are solely responsible for determining the
152+ appropriateness of using or redistributing the Work and assume any
153+ risks associated with Your exercise of permissions under this License.
154+
155+ 8. Limitation of Liability. In no event and under no legal theory,
156+ whether in tort (including negligence), contract, or otherwise,
157+ unless required by applicable law (such as deliberate and grossly
158+ negligent acts) or agreed to in writing, shall any Contributor be
159+ liable to You for damages, including any direct, indirect, special,
160+ incidental, or consequential damages of any character arising as a
161+ result of this License or out of the use or inability to use the
162+ Work (including but not limited to damages for loss of goodwill,
163+ work stoppage, computer failure or malfunction, or any and all
164+ other commercial damages or losses), even if such Contributor
165+ has been advised of the possibility of such damages.
166+
167+ 9. Accepting Warranty or Additional Liability. While redistributing
168+ the Work or Derivative Works thereof, You may choose to offer,
169+ and charge a fee for, acceptance of support, warranty, indemnity,
170+ or other liability obligations and/or rights consistent with this
171+ License. However, in accepting such obligations, You may act only
172+ on Your own behalf and on Your sole responsibility, not on behalf
173+ of any other Contributor, and only if You agree to indemnify,
174+ defend, and hold each Contributor harmless for any liability
175+ incurred by, or claims asserted against, such Contributor by reason
176+ of your accepting any such warranty or additional liability.
177+
178+ END OF TERMS AND CONDITIONS
+44,
-0
1@@ -0,0 +1,44 @@
2+---
3+name: frontend-design
4+description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, web or UI components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
5+---
6+
7+This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
8+
9+The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
10+
11+## Design Thinking
12+
13+Before coding, understand the context and commit to a BOLD aesthetic direction:
14+- **Purpose**: What problem does this interface solve? Who uses it?
15+- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
16+- **Constraints**: Technical requirements (framework, performance, accessibility).
17+- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
18+
19+**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
20+
21+Then implement working code (HTML/CSS/JS only) that is:
22+- Production-grade and functional
23+- Visually striking and memorable
24+- Cohesive with a clear aesthetic point-of-view
25+- Meticulously refined in every detail
26+
27+## Frontend Aesthetics Guidelines
28+
29+Focus on:
30+- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
31+- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
32+- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
33+- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
34+- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
35+
36+NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
37+
38+Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
39+
40+**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
41+
42+Remember: You are capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
43+
44+Related skills:
45+- [playwright-cli](../playwright-cli/SKILL.md): Use the playwright CLI to view and verify your designs
+278,
-0
1@@ -0,0 +1,278 @@
2+---
3+name: playwright-cli
4+description: Automates browser interactions for web testing, form filling, screenshots, and data extraction. Use when the user needs to navigate websites, interact with web pages, fill forms, take screenshots, test web applications, or extract information from web pages.
5+allowed-tools: Bash(playwright-cli:*)
6+---
7+
8+# Browser Automation with playwright-cli
9+
10+## Quick start
11+
12+```bash
13+# open new browser
14+playwright-cli open
15+# navigate to a page
16+playwright-cli goto https://playwright.dev
17+# interact with the page using refs from the snapshot
18+playwright-cli click e15
19+playwright-cli type "page.click"
20+playwright-cli press Enter
21+# take a screenshot (rarely used, as snapshot is more common)
22+playwright-cli screenshot
23+# close the browser
24+playwright-cli close
25+```
26+
27+## Commands
28+
29+### Core
30+
31+```bash
32+playwright-cli open
33+# open and navigate right away
34+playwright-cli open https://example.com/
35+playwright-cli goto https://playwright.dev
36+playwright-cli type "search query"
37+playwright-cli click e3
38+playwright-cli dblclick e7
39+playwright-cli fill e5 "[email protected]"
40+playwright-cli drag e2 e8
41+playwright-cli hover e4
42+playwright-cli select e9 "option-value"
43+playwright-cli upload ./document.pdf
44+playwright-cli check e12
45+playwright-cli uncheck e12
46+playwright-cli snapshot
47+playwright-cli snapshot --filename=after-click.yaml
48+playwright-cli eval "document.title"
49+playwright-cli eval "el => el.textContent" e5
50+playwright-cli dialog-accept
51+playwright-cli dialog-accept "confirmation text"
52+playwright-cli dialog-dismiss
53+playwright-cli resize 1920 1080
54+playwright-cli close
55+```
56+
57+### Navigation
58+
59+```bash
60+playwright-cli go-back
61+playwright-cli go-forward
62+playwright-cli reload
63+```
64+
65+### Keyboard
66+
67+```bash
68+playwright-cli press Enter
69+playwright-cli press ArrowDown
70+playwright-cli keydown Shift
71+playwright-cli keyup Shift
72+```
73+
74+### Mouse
75+
76+```bash
77+playwright-cli mousemove 150 300
78+playwright-cli mousedown
79+playwright-cli mousedown right
80+playwright-cli mouseup
81+playwright-cli mouseup right
82+playwright-cli mousewheel 0 100
83+```
84+
85+### Save as
86+
87+```bash
88+playwright-cli screenshot
89+playwright-cli screenshot e5
90+playwright-cli screenshot --filename=page.png
91+playwright-cli pdf --filename=page.pdf
92+```
93+
94+### Tabs
95+
96+```bash
97+playwright-cli tab-list
98+playwright-cli tab-new
99+playwright-cli tab-new https://example.com/page
100+playwright-cli tab-close
101+playwright-cli tab-close 2
102+playwright-cli tab-select 0
103+```
104+
105+### Storage
106+
107+```bash
108+playwright-cli state-save
109+playwright-cli state-save auth.json
110+playwright-cli state-load auth.json
111+
112+# Cookies
113+playwright-cli cookie-list
114+playwright-cli cookie-list --domain=example.com
115+playwright-cli cookie-get session_id
116+playwright-cli cookie-set session_id abc123
117+playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
118+playwright-cli cookie-delete session_id
119+playwright-cli cookie-clear
120+
121+# LocalStorage
122+playwright-cli localstorage-list
123+playwright-cli localstorage-get theme
124+playwright-cli localstorage-set theme dark
125+playwright-cli localstorage-delete theme
126+playwright-cli localstorage-clear
127+
128+# SessionStorage
129+playwright-cli sessionstorage-list
130+playwright-cli sessionstorage-get step
131+playwright-cli sessionstorage-set step 3
132+playwright-cli sessionstorage-delete step
133+playwright-cli sessionstorage-clear
134+```
135+
136+### Network
137+
138+```bash
139+playwright-cli route "**/*.jpg" --status=404
140+playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
141+playwright-cli route-list
142+playwright-cli unroute "**/*.jpg"
143+playwright-cli unroute
144+```
145+
146+### DevTools
147+
148+```bash
149+playwright-cli console
150+playwright-cli console warning
151+playwright-cli network
152+playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
153+playwright-cli tracing-start
154+playwright-cli tracing-stop
155+playwright-cli video-start
156+playwright-cli video-stop video.webm
157+```
158+
159+## Open parameters
160+```bash
161+# Use specific browser when creating session
162+playwright-cli open --browser=chrome
163+playwright-cli open --browser=firefox
164+playwright-cli open --browser=webkit
165+playwright-cli open --browser=msedge
166+# Connect to browser via extension
167+playwright-cli open --extension
168+
169+# Use persistent profile (by default profile is in-memory)
170+playwright-cli open --persistent
171+# Use persistent profile with custom directory
172+playwright-cli open --profile=/path/to/profile
173+
174+# Start with config file
175+playwright-cli open --config=my-config.json
176+
177+# Close the browser
178+playwright-cli close
179+# Delete user data for the default session
180+playwright-cli delete-data
181+```
182+
183+## Snapshots
184+
185+After each command, playwright-cli provides a snapshot of the current browser state.
186+
187+```bash
188+> playwright-cli goto https://example.com
189+### Page
190+- Page URL: https://example.com/
191+- Page Title: Example Domain
192+### Snapshot
193+[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
194+```
195+
196+You can also take a snapshot on demand using `playwright-cli snapshot` command.
197+
198+If `--filename` is not provided, a new snapshot file is created with a timestamp. Default to automatic file naming, use `--filename=` when artifact is a part of the workflow result.
199+
200+## Browser Sessions
201+
202+```bash
203+# create new browser session named "mysession" with persistent profile
204+playwright-cli -s=mysession open example.com --persistent
205+# same with manually specified profile directory (use when requested explicitly)
206+playwright-cli -s=mysession open example.com --profile=/path/to/profile
207+playwright-cli -s=mysession click e6
208+playwright-cli -s=mysession close # stop a named browser
209+playwright-cli -s=mysession delete-data # delete user data for persistent session
210+
211+playwright-cli list
212+# Close all browsers
213+playwright-cli close-all
214+# Forcefully kill all browser processes
215+playwright-cli kill-all
216+```
217+
218+## Local installation
219+
220+In some cases user might want to install playwright-cli locally. If running globally available `playwright-cli` binary fails, use `npx playwright-cli` to run the commands. For example:
221+
222+```bash
223+npx playwright-cli open https://example.com
224+npx playwright-cli click e1
225+```
226+
227+## Example: Form submission
228+
229+```bash
230+playwright-cli open https://example.com/form
231+playwright-cli snapshot
232+
233+playwright-cli fill e1 "[email protected]"
234+playwright-cli fill e2 "password123"
235+playwright-cli click e3
236+playwright-cli snapshot
237+playwright-cli close
238+```
239+
240+## Example: Multi-tab workflow
241+
242+```bash
243+playwright-cli open https://example.com
244+playwright-cli tab-new https://example.com/other
245+playwright-cli tab-list
246+playwright-cli tab-select 0
247+playwright-cli snapshot
248+playwright-cli close
249+```
250+
251+## Example: Debugging with DevTools
252+
253+```bash
254+playwright-cli open https://example.com
255+playwright-cli click e4
256+playwright-cli fill e7 "test"
257+playwright-cli console
258+playwright-cli network
259+playwright-cli close
260+```
261+
262+```bash
263+playwright-cli open https://example.com
264+playwright-cli tracing-start
265+playwright-cli click e4
266+playwright-cli fill e7 "test"
267+playwright-cli tracing-stop
268+playwright-cli close
269+```
270+
271+## Specific tasks
272+
273+* **Request mocking** [references/request-mocking.md](references/request-mocking.md)
274+* **Running Playwright code** [references/running-code.md](references/running-code.md)
275+* **Browser session management** [references/session-management.md](references/session-management.md)
276+* **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
277+* **Test generation** [references/test-generation.md](references/test-generation.md)
278+* **Tracing** [references/tracing.md](references/tracing.md)
279+* **Video recording** [references/video-recording.md](references/video-recording.md)
1@@ -0,0 +1,87 @@
2+# Request Mocking
3+
4+Intercept, mock, modify, and block network requests.
5+
6+## CLI Route Commands
7+
8+```bash
9+# Mock with custom status
10+playwright-cli route "**/*.jpg" --status=404
11+
12+# Mock with JSON body
13+playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json
14+
15+# Mock with custom headers
16+playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value"
17+
18+# Remove headers from requests
19+playwright-cli route "**/*" --remove-header=cookie,authorization
20+
21+# List active routes
22+playwright-cli route-list
23+
24+# Remove a route or all routes
25+playwright-cli unroute "**/*.jpg"
26+playwright-cli unroute
27+```
28+
29+## URL Patterns
30+
31+```
32+**/api/users - Exact path match
33+**/api/*/details - Wildcard in path
34+**/*.{png,jpg,jpeg} - Match file extensions
35+**/search?q=* - Match query parameters
36+```
37+
38+## Advanced Mocking with run-code
39+
40+For conditional responses, request body inspection, response modification, or delays:
41+
42+### Conditional Response Based on Request
43+
44+```bash
45+playwright-cli run-code "async page => {
46+ await page.route('**/api/login', route => {
47+ const body = route.request().postDataJSON();
48+ if (body.username === 'admin') {
49+ route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) });
50+ } else {
51+ route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) });
52+ }
53+ });
54+}"
55+```
56+
57+### Modify Real Response
58+
59+```bash
60+playwright-cli run-code "async page => {
61+ await page.route('**/api/user', async route => {
62+ const response = await route.fetch();
63+ const json = await response.json();
64+ json.isPremium = true;
65+ await route.fulfill({ response, json });
66+ });
67+}"
68+```
69+
70+### Simulate Network Failures
71+
72+```bash
73+playwright-cli run-code "async page => {
74+ await page.route('**/api/offline', route => route.abort('internetdisconnected'));
75+}"
76+# Options: connectionrefused, timedout, connectionreset, internetdisconnected
77+```
78+
79+### Delayed Response
80+
81+```bash
82+playwright-cli run-code "async page => {
83+ await page.route('**/api/slow', async route => {
84+ await new Promise(r => setTimeout(r, 3000));
85+ route.fulfill({ body: JSON.stringify({ data: 'loaded' }) });
86+ });
87+}"
88+```
1@@ -0,0 +1,232 @@
2+# Running Custom Playwright Code
3+
4+Use `run-code` to execute arbitrary Playwright code for advanced scenarios not covered by CLI commands.
5+
6+## Syntax
7+
8+```bash
9+playwright-cli run-code "async page => {
10+ // Your Playwright code here
11+ // Access page.context() for browser context operations
12+}"
13+```
14+
15+## Geolocation
16+
17+```bash
18+# Grant geolocation permission and set location
19+playwright-cli run-code "async page => {
20+ await page.context().grantPermissions(['geolocation']);
21+ await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
22+}"
23+
24+# Set location to London
25+playwright-cli run-code "async page => {
26+ await page.context().grantPermissions(['geolocation']);
27+ await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
28+}"
29+
30+# Clear geolocation override
31+playwright-cli run-code "async page => {
32+ await page.context().clearPermissions();
33+}"
34+```
35+
36+## Permissions
37+
38+```bash
39+# Grant multiple permissions
40+playwright-cli run-code "async page => {
41+ await page.context().grantPermissions([
42+ 'geolocation',
43+ 'notifications',
44+ 'camera',
45+ 'microphone'
46+ ]);
47+}"
48+
49+# Grant permissions for specific origin
50+playwright-cli run-code "async page => {
51+ await page.context().grantPermissions(['clipboard-read'], {
52+ origin: 'https://example.com'
53+ });
54+}"
55+```
56+
57+## Media Emulation
58+
59+```bash
60+# Emulate dark color scheme
61+playwright-cli run-code "async page => {
62+ await page.emulateMedia({ colorScheme: 'dark' });
63+}"
64+
65+# Emulate light color scheme
66+playwright-cli run-code "async page => {
67+ await page.emulateMedia({ colorScheme: 'light' });
68+}"
69+
70+# Emulate reduced motion
71+playwright-cli run-code "async page => {
72+ await page.emulateMedia({ reducedMotion: 'reduce' });
73+}"
74+
75+# Emulate print media
76+playwright-cli run-code "async page => {
77+ await page.emulateMedia({ media: 'print' });
78+}"
79+```
80+
81+## Wait Strategies
82+
83+```bash
84+# Wait for network idle
85+playwright-cli run-code "async page => {
86+ await page.waitForLoadState('networkidle');
87+}"
88+
89+# Wait for specific element
90+playwright-cli run-code "async page => {
91+ await page.waitForSelector('.loading', { state: 'hidden' });
92+}"
93+
94+# Wait for function to return true
95+playwright-cli run-code "async page => {
96+ await page.waitForFunction(() => window.appReady === true);
97+}"
98+
99+# Wait with timeout
100+playwright-cli run-code "async page => {
101+ await page.waitForSelector('.result', { timeout: 10000 });
102+}"
103+```
104+
105+## Frames and Iframes
106+
107+```bash
108+# Work with iframe
109+playwright-cli run-code "async page => {
110+ const frame = page.locator('iframe#my-iframe').contentFrame();
111+ await frame.locator('button').click();
112+}"
113+
114+# Get all frames
115+playwright-cli run-code "async page => {
116+ const frames = page.frames();
117+ return frames.map(f => f.url());
118+}"
119+```
120+
121+## File Downloads
122+
123+```bash
124+# Handle file download
125+playwright-cli run-code "async page => {
126+ const [download] = await Promise.all([
127+ page.waitForEvent('download'),
128+ page.click('a.download-link')
129+ ]);
130+ await download.saveAs('./downloaded-file.pdf');
131+ return download.suggestedFilename();
132+}"
133+```
134+
135+## Clipboard
136+
137+```bash
138+# Read clipboard (requires permission)
139+playwright-cli run-code "async page => {
140+ await page.context().grantPermissions(['clipboard-read']);
141+ return await page.evaluate(() => navigator.clipboard.readText());
142+}"
143+
144+# Write to clipboard
145+playwright-cli run-code "async page => {
146+ await page.evaluate(text => navigator.clipboard.writeText(text), 'Hello clipboard!');
147+}"
148+```
149+
150+## Page Information
151+
152+```bash
153+# Get page title
154+playwright-cli run-code "async page => {
155+ return await page.title();
156+}"
157+
158+# Get current URL
159+playwright-cli run-code "async page => {
160+ return page.url();
161+}"
162+
163+# Get page content
164+playwright-cli run-code "async page => {
165+ return await page.content();
166+}"
167+
168+# Get viewport size
169+playwright-cli run-code "async page => {
170+ return page.viewportSize();
171+}"
172+```
173+
174+## JavaScript Execution
175+
176+```bash
177+# Execute JavaScript and return result
178+playwright-cli run-code "async page => {
179+ return await page.evaluate(() => {
180+ return {
181+ userAgent: navigator.userAgent,
182+ language: navigator.language,
183+ cookiesEnabled: navigator.cookieEnabled
184+ };
185+ });
186+}"
187+
188+# Pass arguments to evaluate
189+playwright-cli run-code "async page => {
190+ const multiplier = 5;
191+ return await page.evaluate(m => document.querySelectorAll('li').length * m, multiplier);
192+}"
193+```
194+
195+## Error Handling
196+
197+```bash
198+# Try-catch in run-code
199+playwright-cli run-code "async page => {
200+ try {
201+ await page.click('.maybe-missing', { timeout: 1000 });
202+ return 'clicked';
203+ } catch (e) {
204+ return 'element not found';
205+ }
206+}"
207+```
208+
209+## Complex Workflows
210+
211+```bash
212+# Login and save state
213+playwright-cli run-code "async page => {
214+ await page.goto('https://example.com/login');
215+ await page.fill('input[name=email]', '[email protected]');
216+ await page.fill('input[name=password]', 'secret');
217+ await page.click('button[type=submit]');
218+ await page.waitForURL('**/dashboard');
219+ await page.context().storageState({ path: 'auth.json' });
220+ return 'Login successful';
221+}"
222+
223+# Scrape data from multiple pages
224+playwright-cli run-code "async page => {
225+ const results = [];
226+ for (let i = 1; i <= 3; i++) {
227+ await page.goto(\`https://example.com/page/\${i}\`);
228+ const items = await page.locator('.item').allTextContents();
229+ results.push(...items);
230+ }
231+ return results;
232+}"
233+```
1@@ -0,0 +1,169 @@
2+# Browser Session Management
3+
4+Run multiple isolated browser sessions concurrently with state persistence.
5+
6+## Named Browser Sessions
7+
8+Use `-s` flag to isolate browser contexts:
9+
10+```bash
11+# Browser 1: Authentication flow
12+playwright-cli -s=auth open https://app.example.com/login
13+
14+# Browser 2: Public browsing (separate cookies, storage)
15+playwright-cli -s=public open https://example.com
16+
17+# Commands are isolated by browser session
18+playwright-cli -s=auth fill e1 "[email protected]"
19+playwright-cli -s=public snapshot
20+```
21+
22+## Browser Session Isolation Properties
23+
24+Each browser session has independent:
25+- Cookies
26+- LocalStorage / SessionStorage
27+- IndexedDB
28+- Cache
29+- Browsing history
30+- Open tabs
31+
32+## Browser Session Commands
33+
34+```bash
35+# List all browser sessions
36+playwright-cli list
37+
38+# Stop a browser session (close the browser)
39+playwright-cli close # stop the default browser
40+playwright-cli -s=mysession close # stop a named browser
41+
42+# Stop all browser sessions
43+playwright-cli close-all
44+
45+# Forcefully kill all daemon processes (for stale/zombie processes)
46+playwright-cli kill-all
47+
48+# Delete browser session user data (profile directory)
49+playwright-cli delete-data # delete default browser data
50+playwright-cli -s=mysession delete-data # delete named browser data
51+```
52+
53+## Environment Variable
54+
55+Set a default browser session name via environment variable:
56+
57+```bash
58+export PLAYWRIGHT_CLI_SESSION="mysession"
59+playwright-cli open example.com # Uses "mysession" automatically
60+```
61+
62+## Common Patterns
63+
64+### Concurrent Scraping
65+
66+```bash
67+#!/bin/bash
68+# Scrape multiple sites concurrently
69+
70+# Start all browsers
71+playwright-cli -s=site1 open https://site1.com &
72+playwright-cli -s=site2 open https://site2.com &
73+playwright-cli -s=site3 open https://site3.com &
74+wait
75+
76+# Take snapshots from each
77+playwright-cli -s=site1 snapshot
78+playwright-cli -s=site2 snapshot
79+playwright-cli -s=site3 snapshot
80+
81+# Cleanup
82+playwright-cli close-all
83+```
84+
85+### A/B Testing Sessions
86+
87+```bash
88+# Test different user experiences
89+playwright-cli -s=variant-a open "https://app.com?variant=a"
90+playwright-cli -s=variant-b open "https://app.com?variant=b"
91+
92+# Compare
93+playwright-cli -s=variant-a screenshot
94+playwright-cli -s=variant-b screenshot
95+```
96+
97+### Persistent Profile
98+
99+By default, browser profile is kept in memory only. Use `--persistent` flag on `open` to persist the browser profile to disk:
100+
101+```bash
102+# Use persistent profile (auto-generated location)
103+playwright-cli open https://example.com --persistent
104+
105+# Use persistent profile with custom directory
106+playwright-cli open https://example.com --profile=/path/to/profile
107+```
108+
109+## Default Browser Session
110+
111+When `-s` is omitted, commands use the default browser session:
112+
113+```bash
114+# These use the same default browser session
115+playwright-cli open https://example.com
116+playwright-cli snapshot
117+playwright-cli close # Stops default browser
118+```
119+
120+## Browser Session Configuration
121+
122+Configure a browser session with specific settings when opening:
123+
124+```bash
125+# Open with config file
126+playwright-cli open https://example.com --config=.playwright/my-cli.json
127+
128+# Open with specific browser
129+playwright-cli open https://example.com --browser=firefox
130+
131+# Open in headed mode
132+playwright-cli open https://example.com --headed
133+
134+# Open with persistent profile
135+playwright-cli open https://example.com --persistent
136+```
137+
138+## Best Practices
139+
140+### 1. Name Browser Sessions Semantically
141+
142+```bash
143+# GOOD: Clear purpose
144+playwright-cli -s=github-auth open https://github.com
145+playwright-cli -s=docs-scrape open https://docs.example.com
146+
147+# AVOID: Generic names
148+playwright-cli -s=s1 open https://github.com
149+```
150+
151+### 2. Always Clean Up
152+
153+```bash
154+# Stop browsers when done
155+playwright-cli -s=auth close
156+playwright-cli -s=scrape close
157+
158+# Or stop all at once
159+playwright-cli close-all
160+
161+# If browsers become unresponsive or zombie processes remain
162+playwright-cli kill-all
163+```
164+
165+### 3. Delete Stale Browser Data
166+
167+```bash
168+# Remove old browser data to free disk space
169+playwright-cli -s=oldsession delete-data
170+```
1@@ -0,0 +1,275 @@
2+# Storage Management
3+
4+Manage cookies, localStorage, sessionStorage, and browser storage state.
5+
6+## Storage State
7+
8+Save and restore complete browser state including cookies and storage.
9+
10+### Save Storage State
11+
12+```bash
13+# Save to auto-generated filename (storage-state-{timestamp}.json)
14+playwright-cli state-save
15+
16+# Save to specific filename
17+playwright-cli state-save my-auth-state.json
18+```
19+
20+### Restore Storage State
21+
22+```bash
23+# Load storage state from file
24+playwright-cli state-load my-auth-state.json
25+
26+# Reload page to apply cookies
27+playwright-cli open https://example.com
28+```
29+
30+### Storage State File Format
31+
32+The saved file contains:
33+
34+```json
35+{
36+ "cookies": [
37+ {
38+ "name": "session_id",
39+ "value": "abc123",
40+ "domain": "example.com",
41+ "path": "/",
42+ "expires": 1735689600,
43+ "httpOnly": true,
44+ "secure": true,
45+ "sameSite": "Lax"
46+ }
47+ ],
48+ "origins": [
49+ {
50+ "origin": "https://example.com",
51+ "localStorage": [
52+ { "name": "theme", "value": "dark" },
53+ { "name": "user_id", "value": "12345" }
54+ ]
55+ }
56+ ]
57+}
58+```
59+
60+## Cookies
61+
62+### List All Cookies
63+
64+```bash
65+playwright-cli cookie-list
66+```
67+
68+### Filter Cookies by Domain
69+
70+```bash
71+playwright-cli cookie-list --domain=example.com
72+```
73+
74+### Filter Cookies by Path
75+
76+```bash
77+playwright-cli cookie-list --path=/api
78+```
79+
80+### Get Specific Cookie
81+
82+```bash
83+playwright-cli cookie-get session_id
84+```
85+
86+### Set a Cookie
87+
88+```bash
89+# Basic cookie
90+playwright-cli cookie-set session abc123
91+
92+# Cookie with options
93+playwright-cli cookie-set session abc123 --domain=example.com --path=/ --httpOnly --secure --sameSite=Lax
94+
95+# Cookie with expiration (Unix timestamp)
96+playwright-cli cookie-set remember_me token123 --expires=1735689600
97+```
98+
99+### Delete a Cookie
100+
101+```bash
102+playwright-cli cookie-delete session_id
103+```
104+
105+### Clear All Cookies
106+
107+```bash
108+playwright-cli cookie-clear
109+```
110+
111+### Advanced: Multiple Cookies or Custom Options
112+
113+For complex scenarios like adding multiple cookies at once, use `run-code`:
114+
115+```bash
116+playwright-cli run-code "async page => {
117+ await page.context().addCookies([
118+ { name: 'session_id', value: 'sess_abc123', domain: 'example.com', path: '/', httpOnly: true },
119+ { name: 'preferences', value: JSON.stringify({ theme: 'dark' }), domain: 'example.com', path: '/' }
120+ ]);
121+}"
122+```
123+
124+## Local Storage
125+
126+### List All localStorage Items
127+
128+```bash
129+playwright-cli localstorage-list
130+```
131+
132+### Get Single Value
133+
134+```bash
135+playwright-cli localstorage-get token
136+```
137+
138+### Set Value
139+
140+```bash
141+playwright-cli localstorage-set theme dark
142+```
143+
144+### Set JSON Value
145+
146+```bash
147+playwright-cli localstorage-set user_settings '{"theme":"dark","language":"en"}'
148+```
149+
150+### Delete Single Item
151+
152+```bash
153+playwright-cli localstorage-delete token
154+```
155+
156+### Clear All localStorage
157+
158+```bash
159+playwright-cli localstorage-clear
160+```
161+
162+### Advanced: Multiple Operations
163+
164+For complex scenarios like setting multiple values at once, use `run-code`:
165+
166+```bash
167+playwright-cli run-code "async page => {
168+ await page.evaluate(() => {
169+ localStorage.setItem('token', 'jwt_abc123');
170+ localStorage.setItem('user_id', '12345');
171+ localStorage.setItem('expires_at', Date.now() + 3600000);
172+ });
173+}"
174+```
175+
176+## Session Storage
177+
178+### List All sessionStorage Items
179+
180+```bash
181+playwright-cli sessionstorage-list
182+```
183+
184+### Get Single Value
185+
186+```bash
187+playwright-cli sessionstorage-get form_data
188+```
189+
190+### Set Value
191+
192+```bash
193+playwright-cli sessionstorage-set step 3
194+```
195+
196+### Delete Single Item
197+
198+```bash
199+playwright-cli sessionstorage-delete step
200+```
201+
202+### Clear sessionStorage
203+
204+```bash
205+playwright-cli sessionstorage-clear
206+```
207+
208+## IndexedDB
209+
210+### List Databases
211+
212+```bash
213+playwright-cli run-code "async page => {
214+ return await page.evaluate(async () => {
215+ const databases = await indexedDB.databases();
216+ return databases;
217+ });
218+}"
219+```
220+
221+### Delete Database
222+
223+```bash
224+playwright-cli run-code "async page => {
225+ await page.evaluate(() => {
226+ indexedDB.deleteDatabase('myDatabase');
227+ });
228+}"
229+```
230+
231+## Common Patterns
232+
233+### Authentication State Reuse
234+
235+```bash
236+# Step 1: Login and save state
237+playwright-cli open https://app.example.com/login
238+playwright-cli snapshot
239+playwright-cli fill e1 "[email protected]"
240+playwright-cli fill e2 "password123"
241+playwright-cli click e3
242+
243+# Save the authenticated state
244+playwright-cli state-save auth.json
245+
246+# Step 2: Later, restore state and skip login
247+playwright-cli state-load auth.json
248+playwright-cli open https://app.example.com/dashboard
249+# Already logged in!
250+```
251+
252+### Save and Restore Roundtrip
253+
254+```bash
255+# Set up authentication state
256+playwright-cli open https://example.com
257+playwright-cli eval "() => { document.cookie = 'session=abc123'; localStorage.setItem('user', 'john'); }"
258+
259+# Save state to file
260+playwright-cli state-save my-session.json
261+
262+# ... later, in a new session ...
263+
264+# Restore state
265+playwright-cli state-load my-session.json
266+playwright-cli open https://example.com
267+# Cookies and localStorage are restored!
268+```
269+
270+## Security Notes
271+
272+- Never commit storage state files containing auth tokens
273+- Add `*.auth-state.json` to `.gitignore`
274+- Delete state files after automation completes
275+- Use environment variables for sensitive data
276+- By default, sessions run in-memory mode which is safer for sensitive operations
1@@ -0,0 +1,88 @@
2+# Test Generation
3+
4+Generate Playwright test code automatically as you interact with the browser.
5+
6+## How It Works
7+
8+Every action you perform with `playwright-cli` generates corresponding Playwright TypeScript code.
9+This code appears in the output and can be copied directly into your test files.
10+
11+## Example Workflow
12+
13+```bash
14+# Start a session
15+playwright-cli open https://example.com/login
16+
17+# Take a snapshot to see elements
18+playwright-cli snapshot
19+# Output shows: e1 [textbox "Email"], e2 [textbox "Password"], e3 [button "Sign In"]
20+
21+# Fill form fields - generates code automatically
22+playwright-cli fill e1 "[email protected]"
23+# Ran Playwright code:
24+# await page.getByRole('textbox', { name: 'Email' }).fill('[email protected]');
25+
26+playwright-cli fill e2 "password123"
27+# Ran Playwright code:
28+# await page.getByRole('textbox', { name: 'Password' }).fill('password123');
29+
30+playwright-cli click e3
31+# Ran Playwright code:
32+# await page.getByRole('button', { name: 'Sign In' }).click();
33+```
34+
35+## Building a Test File
36+
37+Collect the generated code into a Playwright test:
38+
39+```typescript
40+import { test, expect } from '@playwright/test';
41+
42+test('login flow', async ({ page }) => {
43+ // Generated code from playwright-cli session:
44+ await page.goto('https://example.com/login');
45+ await page.getByRole('textbox', { name: 'Email' }).fill('[email protected]');
46+ await page.getByRole('textbox', { name: 'Password' }).fill('password123');
47+ await page.getByRole('button', { name: 'Sign In' }).click();
48+
49+ // Add assertions
50+ await expect(page).toHaveURL(/.*dashboard/);
51+});
52+```
53+
54+## Best Practices
55+
56+### 1. Use Semantic Locators
57+
58+The generated code uses role-based locators when possible, which are more resilient:
59+
60+```typescript
61+// Generated (good - semantic)
62+await page.getByRole('button', { name: 'Submit' }).click();
63+
64+// Avoid (fragile - CSS selectors)
65+await page.locator('#submit-btn').click();
66+```
67+
68+### 2. Explore Before Recording
69+
70+Take snapshots to understand the page structure before recording actions:
71+
72+```bash
73+playwright-cli open https://example.com
74+playwright-cli snapshot
75+# Review the element structure
76+playwright-cli click e5
77+```
78+
79+### 3. Add Assertions Manually
80+
81+Generated code captures actions but not assertions. Add expectations in your test:
82+
83+```typescript
84+// Generated action
85+await page.getByRole('button', { name: 'Submit' }).click();
86+
87+// Manual assertion
88+await expect(page.getByText('Success')).toBeVisible();
89+```
+139,
-0
1@@ -0,0 +1,139 @@
2+# Tracing
3+
4+Capture detailed execution traces for debugging and analysis. Traces include DOM snapshots, screenshots, network activity, and console logs.
5+
6+## Basic Usage
7+
8+```bash
9+# Start trace recording
10+playwright-cli tracing-start
11+
12+# Perform actions
13+playwright-cli open https://example.com
14+playwright-cli click e1
15+playwright-cli fill e2 "test"
16+
17+# Stop trace recording
18+playwright-cli tracing-stop
19+```
20+
21+## Trace Output Files
22+
23+When you start tracing, Playwright creates a `traces/` directory with several files:
24+
25+### `trace-{timestamp}.trace`
26+
27+**Action log** - The main trace file containing:
28+- Every action performed (clicks, fills, navigations)
29+- DOM snapshots before and after each action
30+- Screenshots at each step
31+- Timing information
32+- Console messages
33+- Source locations
34+
35+### `trace-{timestamp}.network`
36+
37+**Network log** - Complete network activity:
38+- All HTTP requests and responses
39+- Request headers and bodies
40+- Response headers and bodies
41+- Timing (DNS, connect, TLS, TTFB, download)
42+- Resource sizes
43+- Failed requests and errors
44+
45+### `resources/`
46+
47+**Resources directory** - Cached resources:
48+- Images, fonts, stylesheets, scripts
49+- Response bodies for replay
50+- Assets needed to reconstruct page state
51+
52+## What Traces Capture
53+
54+| Category | Details |
55+|----------|---------|
56+| **Actions** | Clicks, fills, hovers, keyboard input, navigations |
57+| **DOM** | Full DOM snapshot before/after each action |
58+| **Screenshots** | Visual state at each step |
59+| **Network** | All requests, responses, headers, bodies, timing |
60+| **Console** | All console.log, warn, error messages |
61+| **Timing** | Precise timing for each operation |
62+
63+## Use Cases
64+
65+### Debugging Failed Actions
66+
67+```bash
68+playwright-cli tracing-start
69+playwright-cli open https://app.example.com
70+
71+# This click fails - why?
72+playwright-cli click e5
73+
74+playwright-cli tracing-stop
75+# Open trace to see DOM state when click was attempted
76+```
77+
78+### Analyzing Performance
79+
80+```bash
81+playwright-cli tracing-start
82+playwright-cli open https://slow-site.com
83+playwright-cli tracing-stop
84+
85+# View network waterfall to identify slow resources
86+```
87+
88+### Capturing Evidence
89+
90+```bash
91+# Record a complete user flow for documentation
92+playwright-cli tracing-start
93+
94+playwright-cli open https://app.example.com/checkout
95+playwright-cli fill e1 "4111111111111111"
96+playwright-cli fill e2 "12/25"
97+playwright-cli fill e3 "123"
98+playwright-cli click e4
99+
100+playwright-cli tracing-stop
101+# Trace shows exact sequence of events
102+```
103+
104+## Trace vs Video vs Screenshot
105+
106+| Feature | Trace | Video | Screenshot |
107+|---------|-------|-------|------------|
108+| **Format** | .trace file | .webm video | .png/.jpeg image |
109+| **DOM inspection** | Yes | No | No |
110+| **Network details** | Yes | No | No |
111+| **Step-by-step replay** | Yes | Continuous | Single frame |
112+| **File size** | Medium | Large | Small |
113+| **Best for** | Debugging | Demos | Quick capture |
114+
115+## Best Practices
116+
117+### 1. Start Tracing Before the Problem
118+
119+```bash
120+# Trace the entire flow, not just the failing step
121+playwright-cli tracing-start
122+playwright-cli open https://example.com
123+# ... all steps leading to the issue ...
124+playwright-cli tracing-stop
125+```
126+
127+### 2. Clean Up Old Traces
128+
129+Traces can consume significant disk space:
130+
131+```bash
132+# Remove traces older than 7 days
133+find .playwright-cli/traces -mtime +7 -delete
134+```
135+
136+## Limitations
137+
138+- Traces add overhead to automation
139+- Large traces can consume significant disk space
140+- Some dynamic content may not replay perfectly
1@@ -0,0 +1,43 @@
2+# Video Recording
3+
4+Capture browser automation sessions as video for debugging, documentation, or verification. Produces WebM (VP8/VP9 codec).
5+
6+## Basic Recording
7+
8+```bash
9+# Start recording
10+playwright-cli video-start
11+
12+# Perform actions
13+playwright-cli open https://example.com
14+playwright-cli snapshot
15+playwright-cli click e1
16+playwright-cli fill e2 "test input"
17+
18+# Stop and save
19+playwright-cli video-stop demo.webm
20+```
21+
22+## Best Practices
23+
24+### 1. Use Descriptive Filenames
25+
26+```bash
27+# Include context in filename
28+playwright-cli video-stop recordings/login-flow-2024-01-15.webm
29+playwright-cli video-stop recordings/checkout-test-run-42.webm
30+```
31+
32+## Tracing vs Video
33+
34+| Feature | Video | Tracing |
35+|---------|-------|---------|
36+| Output | WebM file | Trace file (viewable in Trace Viewer) |
37+| Shows | Visual recording | DOM snapshots, network, console, actions |
38+| Use case | Demos, documentation | Debugging, analysis |
39+| Size | Larger | Smaller |
40+
41+## Limitations
42+
43+- Recording adds slight overhead to automation
44+- Large recordings can consume significant disk space
+100,
-0
1@@ -0,0 +1,100 @@
2+---
3+name: brainstorming
4+description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
5+---
6+
7+# Brainstorming Ideas Into Designs
8+
9+## Overview
10+
11+Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
12+
13+Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval.
14+
15+<HARD-GATE>
16+Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity.
17+</HARD-GATE>
18+
19+## Anti-Pattern: "This Is Too Simple To Need A Design"
20+
21+Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval.
22+
23+## Checklist
24+
25+You MUST create a task for each of these items and complete them in order:
26+
27+1. **Explore project context** — check files, docs, recent commits
28+2. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria
29+3. **Propose 2-3 approaches** — with trade-offs and your recommendation
30+4. **Present design** — in sections scaled to their complexity, get user approval after each section
31+5. **Write design doc** — save to `docs/plans/YYYY-MM-DD-<topic>-design.md` and commit
32+6. **Transition to implementation** — invoke writing-plans skill to create implementation plan
33+
34+## Process Flow
35+
36+```dot
37+digraph brainstorming {
38+ "Explore project context" [shape=box];
39+ "Ask clarifying questions" [shape=box];
40+ "Propose 2-3 approaches" [shape=box];
41+ "Present design sections" [shape=box];
42+ "User approves design?" [shape=diamond];
43+ "Write design doc" [shape=box];
44+ "Invoke writing-plans skill" [shape=doublecircle];
45+
46+ "Explore project context" -> "Ask clarifying questions";
47+ "Ask clarifying questions" -> "Propose 2-3 approaches";
48+ "Propose 2-3 approaches" -> "Present design sections";
49+ "Present design sections" -> "User approves design?";
50+ "User approves design?" -> "Present design sections" [label="no, revise"];
51+ "User approves design?" -> "Write design doc" [label="yes"];
52+ "Write design doc" -> "Invoke writing-plans skill";
53+}
54+```
55+
56+**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans.
57+
58+## The Process
59+
60+**Understanding the idea:**
61+- Check out the current project state first (files, docs, recent commits)
62+- Ask questions one at a time to refine the idea
63+- Prefer multiple choice questions when possible, but open-ended is fine too
64+- Only one question per message - if a topic needs more exploration, break it into multiple questions
65+- Focus on understanding: purpose, constraints, success criteria
66+
67+**Exploring approaches:**
68+- Propose 2-3 different approaches with trade-offs
69+- Present options conversationally with your recommendation and reasoning
70+- Lead with your recommended option and explain why
71+
72+**Presenting the design:**
73+- Once you believe you understand what you're building, present the design
74+- Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced
75+- Ask after each section whether it looks right so far
76+- Cover: architecture, components, data flow, error handling, testing
77+- Be ready to go back and clarify if something doesn't make sense
78+
79+## After the Design
80+
81+**Documentation:**
82+- Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md`
83+- Use elements-of-style:writing-clearly-and-concisely skill if available
84+- **REQUIRED SUB-SKILL:** Use `working-with-jj` to commit the design document:
85+ ```
86+ jj commit -m "docs: add design for <topic>"
87+ ```
88+
89+**Implementation:**
90+- Invoke the writing-plans skill to create a detailed implementation plan
91+- Do NOT invoke any other skill. writing-plans is the next step.
92+- **REQUIRED:** The writing-plans skill will use `working-with-jj` for all version control operations
93+
94+## Key Principles
95+
96+- **One question at a time** - Don't overwhelm with multiple questions
97+- **Multiple choice preferred** - Easier to answer than open-ended when possible
98+- **YAGNI ruthlessly** - Remove unnecessary features from all designs
99+- **Explore alternatives** - Always propose 2-3 approaches before settling
100+- **Incremental validation** - Present design, get approval before moving on
101+- **Be flexible** - Go back and clarify when something doesn't make sense
1@@ -0,0 +1,180 @@
2+---
3+name: dispatching-parallel-agents
4+description: Use when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies
5+---
6+
7+# Dispatching Parallel Agents
8+
9+## Overview
10+
11+When you have multiple unrelated failures (different test files, different subsystems, different bugs), investigating them sequentially wastes time. Each investigation is independent and can happen in parallel.
12+
13+**Core principle:** Dispatch one agent per independent problem domain. Let them work concurrently.
14+
15+## When to Use
16+
17+```dot
18+digraph when_to_use {
19+ "Multiple failures?" [shape=diamond];
20+ "Are they independent?" [shape=diamond];
21+ "Single agent investigates all" [shape=box];
22+ "One agent per problem domain" [shape=box];
23+ "Can they work in parallel?" [shape=diamond];
24+ "Sequential agents" [shape=box];
25+ "Parallel dispatch" [shape=box];
26+
27+ "Multiple failures?" -> "Are they independent?" [label="yes"];
28+ "Are they independent?" -> "Single agent investigates all" [label="no - related"];
29+ "Are they independent?" -> "Can they work in parallel?" [label="yes"];
30+ "Can they work in parallel?" -> "Parallel dispatch" [label="yes"];
31+ "Can they work in parallel?" -> "Sequential agents" [label="no - shared state"];
32+}
33+```
34+
35+**Use when:**
36+- 3+ test files failing with different root causes
37+- Multiple subsystems broken independently
38+- Each problem can be understood without context from others
39+- No shared state between investigations
40+
41+**Don't use when:**
42+- Failures are related (fix one might fix others)
43+- Need to understand full system state
44+- Agents would interfere with each other
45+
46+## The Pattern
47+
48+### 1. Identify Independent Domains
49+
50+Group failures by what's broken:
51+- File A tests: Tool approval flow
52+- File B tests: Batch completion behavior
53+- File C tests: Abort functionality
54+
55+Each domain is independent - fixing tool approval doesn't affect abort tests.
56+
57+### 2. Create Focused Agent Tasks
58+
59+Each agent gets:
60+- **Specific scope:** One test file or subsystem
61+- **Clear goal:** Make these tests pass
62+- **Constraints:** Don't change other code
63+- **Expected output:** Summary of what you found and fixed
64+
65+### 3. Dispatch in Parallel
66+
67+```typescript
68+// In Claude Code / AI environment
69+Task("Fix agent-tool-abort.test.ts failures")
70+Task("Fix batch-completion-behavior.test.ts failures")
71+Task("Fix tool-approval-race-conditions.test.ts failures")
72+// All three run concurrently
73+```
74+
75+### 4. Review and Integrate
76+
77+When agents return:
78+- Read each summary
79+- Verify fixes don't conflict
80+- Run full test suite
81+- Integrate all changes
82+
83+## Agent Prompt Structure
84+
85+Good agent prompts are:
86+1. **Focused** - One clear problem domain
87+2. **Self-contained** - All context needed to understand the problem
88+3. **Specific about output** - What should the agent return?
89+
90+```markdown
91+Fix the 3 failing tests in src/agents/agent-tool-abort.test.ts:
92+
93+1. "should abort tool with partial output capture" - expects 'interrupted at' in message
94+2. "should handle mixed completed and aborted tools" - fast tool aborted instead of completed
95+3. "should properly track pendingToolCount" - expects 3 results but gets 0
96+
97+These are timing/race condition issues. Your task:
98+
99+1. Read the test file and understand what each test verifies
100+2. Identify root cause - timing issues or actual bugs?
101+3. Fix by:
102+ - Replacing arbitrary timeouts with event-based waiting
103+ - Fixing bugs in abort implementation if found
104+ - Adjusting test expectations if testing changed behavior
105+
106+Do NOT just increase timeouts - find the real issue.
107+
108+Return: Summary of what you found and what you fixed.
109+```
110+
111+## Common Mistakes
112+
113+**❌ Too broad:** "Fix all the tests" - agent gets lost
114+**✅ Specific:** "Fix agent-tool-abort.test.ts" - focused scope
115+
116+**❌ No context:** "Fix the race condition" - agent doesn't know where
117+**✅ Context:** Paste the error messages and test names
118+
119+**❌ No constraints:** Agent might refactor everything
120+**✅ Constraints:** "Do NOT change production code" or "Fix tests only"
121+
122+**❌ Vague output:** "Fix it" - you don't know what changed
123+**✅ Specific:** "Return summary of root cause and changes"
124+
125+## When NOT to Use
126+
127+**Related failures:** Fixing one might fix others - investigate together first
128+**Need full context:** Understanding requires seeing entire system
129+**Exploratory debugging:** You don't know what's broken yet
130+**Shared state:** Agents would interfere (editing same files, using same resources)
131+
132+## Real Example from Session
133+
134+**Scenario:** 6 test failures across 3 files after major refactoring
135+
136+**Failures:**
137+- agent-tool-abort.test.ts: 3 failures (timing issues)
138+- batch-completion-behavior.test.ts: 2 failures (tools not executing)
139+- tool-approval-race-conditions.test.ts: 1 failure (execution count = 0)
140+
141+**Decision:** Independent domains - abort logic separate from batch completion separate from race conditions
142+
143+**Dispatch:**
144+```
145+Agent 1 → Fix agent-tool-abort.test.ts
146+Agent 2 → Fix batch-completion-behavior.test.ts
147+Agent 3 → Fix tool-approval-race-conditions.test.ts
148+```
149+
150+**Results:**
151+- Agent 1: Replaced timeouts with event-based waiting
152+- Agent 2: Fixed event structure bug (threadId in wrong place)
153+- Agent 3: Added wait for async tool execution to complete
154+
155+**Integration:** All fixes independent, no conflicts, full suite green
156+
157+**Time saved:** 3 problems solved in parallel vs sequentially
158+
159+## Key Benefits
160+
161+1. **Parallelization** - Multiple investigations happen simultaneously
162+2. **Focus** - Each agent has narrow scope, less context to track
163+3. **Independence** - Agents don't interfere with each other
164+4. **Speed** - 3 problems solved in time of 1
165+
166+## Verification
167+
168+After agents return:
169+1. **Review each summary** - Understand what changed
170+2. **Check for conflicts** - Did agents edit same code?
171+3. **Run full suite** - Verify all fixes work together
172+4. **Spot check** - Agents can make systematic errors
173+
174+## Real-World Impact
175+
176+From debugging session (2025-10-03):
177+- 6 failures across 3 files
178+- 3 agents dispatched in parallel
179+- All investigations completed concurrently
180+- All fixes integrated successfully
181+- Zero conflicts between agent changes
1@@ -0,0 +1,84 @@
2+---
3+name: executing-plans
4+description: Use when you have a written implementation plan to execute in a separate session with review checkpoints
5+---
6+
7+# Executing Plans
8+
9+## Overview
10+
11+Load plan, review critically, execute tasks in batches, report for review between batches.
12+
13+**Core principle:** Batch execution with checkpoints for architect review.
14+
15+**Announce at start:** "I'm using the executing-plans skill to implement this plan."
16+
17+## The Process
18+
19+### Step 1: Load and Review Plan
20+1. Read plan file
21+2. Review critically - identify any questions or concerns about the plan
22+3. If concerns: Raise them with your human partner before starting
23+4. If no concerns: Create TodoWrite and proceed
24+
25+### Step 2: Execute Batch
26+**Default: First 3 tasks**
27+
28+For each task:
29+1. Mark as in_progress
30+2. Follow each step exactly (plan has bite-sized steps)
31+3. Run verifications as specified
32+4. Mark as completed
33+
34+### Step 3: Report
35+When batch complete:
36+- Show what was implemented
37+- Show verification output
38+- Say: "Ready for feedback."
39+
40+### Step 4: Continue
41+Based on feedback:
42+- Apply changes if needed
43+- Execute next batch
44+- Repeat until complete
45+
46+### Step 5: Complete Development
47+
48+After all tasks complete and verified:
49+- Run final verification (tests, lint, build, type check)
50+- Review changes with `jj diff`
51+- Present summary to user for approval
52+- Upon approval, the changes are ready for the user to manage (squash, rebase, push as desired)
53+
54+## When to Stop and Ask for Help
55+
56+**STOP executing immediately when:**
57+- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear)
58+- Plan has critical gaps preventing starting
59+- You don't understand an instruction
60+- Verification fails repeatedly
61+
62+**Ask for clarification rather than guessing.**
63+
64+## When to Revisit Earlier Steps
65+
66+**Return to Review (Step 1) when:**
67+- Partner updates the plan based on your feedback
68+- Fundamental approach needs rethinking
69+
70+**Don't force through blockers** - stop and ask.
71+
72+## Remember
73+- Review plan critically first
74+- Follow plan steps exactly
75+- Don't skip verifications
76+- Reference skills when plan says to
77+- Between batches: just report and wait
78+- Stop when blocked, don't guess
79+- Never start implementation on main/master branch without explicit user consent
80+
81+## Integration
82+
83+**Required workflow skills:**
84+- **working-with-jj** - REQUIRED: Set up new jj change before starting
85+- **superpowers:writing-plans** - Creates the plan this skill executes
1@@ -0,0 +1,209 @@
2+---
3+name: receiving-code-review
4+description: Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation
5+---
6+
7+# Code Review Reception
8+
9+## Overview
10+
11+Code review requires technical evaluation, not emotional performance.
12+
13+**Core principle:** Verify before implementing. Ask before assuming. Technical correctness over social comfort.
14+
15+## The Response Pattern
16+
17+```
18+WHEN receiving code review feedback:
19+
20+1. READ: Complete feedback without reacting
21+2. UNDERSTAND: Restate requirement in own words (or ask)
22+3. VERIFY: Check against codebase reality
23+4. EVALUATE: Technically sound for THIS codebase?
24+5. RESPOND: Technical acknowledgment or reasoned pushback
25+6. IMPLEMENT: One item at a time, test each
26+```
27+
28+## Forbidden Responses
29+
30+**NEVER:**
31+- "You're absolutely right!" (explicit AGENTS.md violation)
32+- "Great point!" / "Excellent feedback!" (performative)
33+- "Let me implement that now" (before verification)
34+
35+**INSTEAD:**
36+- Restate the technical requirement
37+- Ask clarifying questions
38+- Push back with technical reasoning if wrong
39+- Just start working (actions > words)
40+
41+## Handling Unclear Feedback
42+
43+```
44+IF any item is unclear:
45+ STOP - do not implement anything yet
46+ ASK for clarification on unclear items
47+
48+WHY: Items may be related. Partial understanding = wrong implementation.
49+```
50+
51+**Example:**
52+```
53+your human partner: "Fix 1-6"
54+You understand 1,2,3,6. Unclear on 4,5.
55+
56+❌ WRONG: Implement 1,2,3,6 now, ask about 4,5 later
57+✅ RIGHT: "I understand items 1,2,3,6. Need clarification on 4 and 5 before proceeding."
58+```
59+
60+## Source-Specific Handling
61+
62+### From your human partner
63+- **Trusted** - implement after understanding
64+- **Still ask** if scope unclear
65+- **No performative agreement**
66+- **Skip to action** or technical acknowledgment
67+
68+### From External Reviewers
69+```
70+BEFORE implementing:
71+ 1. Check: Technically correct for THIS codebase?
72+ 2. Check: Breaks existing functionality?
73+ 3. Check: Reason for current implementation?
74+ 4. Check: Works on all platforms/versions?
75+ 5. Check: Does reviewer understand full context?
76+
77+IF suggestion seems wrong:
78+ Push back with technical reasoning
79+
80+IF can't easily verify:
81+ Say so: "I can't verify this without [X]. Should I [investigate/ask/proceed]?"
82+
83+IF conflicts with your human partner's prior decisions:
84+ Stop and discuss with your human partner first
85+```
86+
87+**your human partner's rule:** "External feedback - be skeptical, but check carefully"
88+
89+## YAGNI Check for "Professional" Features
90+
91+```
92+IF reviewer suggests "implementing properly":
93+ grep codebase for actual usage
94+
95+ IF unused: "This endpoint isn't called. Remove it (YAGNI)?"
96+ IF used: Then implement properly
97+```
98+
99+**your human partner's rule:** "You and reviewer both report to me. If we don't need this feature, don't add it."
100+
101+## Implementation Order
102+
103+```
104+FOR multi-item feedback:
105+ 1. Clarify anything unclear FIRST
106+ 2. Then implement in this order:
107+ - Blocking issues (breaks, security)
108+ - Simple fixes (typos, imports)
109+ - Complex fixes (refactoring, logic)
110+ 3. Test each fix individually
111+ 4. Verify no regressions
112+```
113+
114+## When To Push Back
115+
116+Push back when:
117+- Suggestion breaks existing functionality
118+- Reviewer lacks full context
119+- Violates YAGNI (unused feature)
120+- Technically incorrect for this stack
121+- Legacy/compatibility reasons exist
122+- Conflicts with your human partner's architectural decisions
123+
124+**How to push back:**
125+- Use technical reasoning, not defensiveness
126+- Ask specific questions
127+- Reference working tests/code
128+- Involve your human partner if architectural
129+
130+**Signal if uncomfortable pushing back out loud:** "Strange things are afoot at the Circle K"
131+
132+## Acknowledging Correct Feedback
133+
134+When feedback IS correct:
135+```
136+✅ "Fixed. [Brief description of what changed]"
137+✅ "Good catch - [specific issue]. Fixed in [location]."
138+✅ [Just fix it and show in the code]
139+
140+❌ "You're absolutely right!"
141+❌ "Great point!"
142+❌ "Thanks for catching that!"
143+❌ "Thanks for [anything]"
144+❌ ANY gratitude expression
145+```
146+
147+**Why no thanks:** Actions speak. Just fix it. The code itself shows you heard the feedback.
148+
149+**If you catch yourself about to write "Thanks":** DELETE IT. State the fix instead.
150+
151+## Gracefully Correcting Your Pushback
152+
153+If you pushed back and were wrong:
154+```
155+✅ "You were right - I checked [X] and it does [Y]. Implementing now."
156+✅ "Verified this and you're correct. My initial understanding was wrong because [reason]. Fixing."
157+
158+❌ Long apology
159+❌ Defending why you pushed back
160+❌ Over-explaining
161+```
162+
163+State the correction factually and move on.
164+
165+## Common Mistakes
166+
167+| Mistake | Fix |
168+|---------|-----|
169+| Performative agreement | State requirement or just act |
170+| Blind implementation | Verify against codebase first |
171+| Batch without testing | One at a time, test each |
172+| Assuming reviewer is right | Check if breaks things |
173+| Avoiding pushback | Technical correctness > comfort |
174+| Partial implementation | Clarify all items first |
175+| Can't verify, proceed anyway | State limitation, ask for direction |
176+
177+## Real Examples
178+
179+**Performative Agreement (Bad):**
180+```
181+Reviewer: "Remove legacy code"
182+❌ "You're absolutely right! Let me remove that..."
183+```
184+
185+**Technical Verification (Good):**
186+```
187+Reviewer: "Remove legacy code"
188+✅ "Checking... build target is 10.15+, this API needs 13+. Need legacy for backward compat. Current impl has wrong bundle ID - fix it or drop pre-13 support?"
189+```
190+
191+**YAGNI (Good):**
192+```
193+Reviewer: "Implement proper metrics tracking with database, date filters, CSV export"
194+✅ "Grepped codebase - nothing calls this endpoint. Remove it (YAGNI)? Or is there usage I'm missing?"
195+```
196+
197+**Unclear Item (Good):**
198+```
199+your human partner: "Fix items 1-6"
200+You understand 1,2,3,6. Unclear on 4,5.
201+✅ "Understand 1,2,3,6. Need clarification on 4 and 5 before implementing."
202+```
203+
204+## The Bottom Line
205+
206+**External feedback = suggestions to evaluate, not orders to follow.**
207+
208+Verify. Question. Then implement.
209+
210+No performative agreement. Technical rigor always.
1@@ -0,0 +1,105 @@
2+---
3+name: requesting-code-review
4+description: Use when completing tasks, implementing major features, or before merging to verify work meets requirements
5+---
6+
7+# Requesting Code Review
8+
9+Dispatch superpowers:code-reviewer subagent to catch issues before they cascade.
10+
11+**Core principle:** Review early, review often.
12+
13+## When to Request Review
14+
15+**Mandatory:**
16+- After each task in subagent-driven development
17+- After completing major feature
18+- Before merge to main
19+
20+**Optional but valuable:**
21+- When stuck (fresh perspective)
22+- Before refactoring (baseline check)
23+- After fixing complex bug
24+
25+## How to Request
26+
27+**1. Get jj change IDs:**
28+```bash
29+BASE_CHANGE=$(jj log -r @- -G -T "change_id")
30+REVIEW_CHANGE=$(jj log -r @ -G -T "change_id")
31+```
32+
33+**2. Dispatch code-reviewer subagent:**
34+
35+Use Task tool with superpowers:code-reviewer type, fill template at `code-reviewer.md`
36+
37+**Placeholders:**
38+- `{WHAT_WAS_IMPLEMENTED}` - What you just built
39+- `{PLAN_OR_REQUIREMENTS}` - What it should do
40+- `{BASE_CHANGE}` - Starting commit
41+- `{REVIEW_CHANGE}` - Ending commit
42+- `{DESCRIPTION}` - Brief summary
43+
44+**3. Act on feedback:**
45+- Fix Critical issues immediately
46+- Fix Important issues before proceeding
47+- Note Minor issues for later
48+- Push back if reviewer is wrong (with reasoning)
49+
50+## Example
51+
52+```
53+[Just completed Task 2: Add verification function]
54+
55+You: Let me request code review before proceeding.
56+
57+BASE_CHANGE=$(jj log -r @- -G -T "change_id")
58+REVIEW_CHANGE=$(jj log -r @ -G -T "change_id")
59+
60+[Dispatch superpowers:code-reviewer subagent]
61+ WHAT_WAS_IMPLEMENTED: Verification and repair functions for conversation index
62+ PLAN_OR_REQUIREMENTS: Task 2 from docs/plans/deployment-plan.md
63+ BASE_CHANGE: qlqmutkktmxxwsrvpxkqxzmtrpmnnryv
64+ REVIEW_CHANGE: rvmqymolrwulxowxwlsnvxsslmnlvoxr
65+ DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types
66+
67+[Subagent returns]:
68+ Strengths: Clean architecture, real tests
69+ Issues:
70+ Important: Missing progress indicators
71+ Minor: Magic number (100) for reporting interval
72+ Assessment: Ready to proceed
73+
74+You: [Fix progress indicators]
75+[Continue to Task 3]
76+```
77+
78+## Integration with Workflows
79+
80+**Subagent-Driven Development:**
81+- Review after EACH task
82+- Catch issues before they compound
83+- Fix before moving to next task
84+
85+**Executing Plans:**
86+- Review after each batch (3 tasks)
87+- Get feedback, apply, continue
88+
89+**Ad-Hoc Development:**
90+- Review before merge
91+- Review when stuck
92+
93+## Red Flags
94+
95+**Never:**
96+- Skip review because "it's simple"
97+- Ignore Critical issues
98+- Proceed with unfixed Important issues
99+- Argue with valid technical feedback
100+
101+**If reviewer wrong:**
102+- Push back with technical reasoning
103+- Show code/tests that prove it works
104+- Request clarification
105+
106+See template at: requesting-code-review/code-reviewer.md
1@@ -0,0 +1,146 @@
2+# Code Review Agent
3+
4+You are reviewing code changes for production readiness.
5+
6+**Your task:**
7+1. Review {WHAT_WAS_IMPLEMENTED}
8+2. Compare against {PLAN_OR_REQUIREMENTS}
9+3. Check code quality, architecture, testing
10+4. Categorize issues by severity
11+5. Assess production readiness
12+
13+## What Was Implemented
14+
15+{DESCRIPTION}
16+
17+## Requirements/Plan
18+
19+{PLAN_REFERENCE}
20+
21+## Git Range to Review
22+
23+**Base:** {BASE_CHANGE}
24+**Review:** {REVIEW_CHANGE}
25+
26+```bash
27+jj diff --stat --color never -r {BASE_CHANGE}::{REVIEW_CHANGE}
28+jj diff --color never --no-pager -r {BASE_CHANGE}::{REVIEW_CHANGE}
29+```
30+
31+## Review Checklist
32+
33+**Code Quality:**
34+- Clean separation of concerns?
35+- Proper error handling?
36+- Type safety (if applicable)?
37+- DRY principle followed?
38+- Edge cases handled?
39+
40+**Architecture:**
41+- Sound design decisions?
42+- Scalability considerations?
43+- Performance implications?
44+- Security concerns?
45+
46+**Testing:**
47+- Tests actually test logic (not mocks)?
48+- Edge cases covered?
49+- Integration tests where needed?
50+- All tests passing?
51+
52+**Requirements:**
53+- All plan requirements met?
54+- Implementation matches spec?
55+- No scope creep?
56+- Breaking changes documented?
57+
58+**Production Readiness:**
59+- Migration strategy (if schema changes)?
60+- Backward compatibility considered?
61+- Documentation complete?
62+- No obvious bugs?
63+
64+## Output Format
65+
66+### Strengths
67+[What's well done? Be specific.]
68+
69+### Issues
70+
71+#### Critical (Must Fix)
72+[Bugs, security issues, data loss risks, broken functionality]
73+
74+#### Important (Should Fix)
75+[Architecture problems, missing features, poor error handling, test gaps]
76+
77+#### Minor (Nice to Have)
78+[Code style, optimization opportunities, documentation improvements]
79+
80+**For each issue:**
81+- File:line reference
82+- What's wrong
83+- Why it matters
84+- How to fix (if not obvious)
85+
86+### Recommendations
87+[Improvements for code quality, architecture, or process]
88+
89+### Assessment
90+
91+**Ready to merge?** [Yes/No/With fixes]
92+
93+**Reasoning:** [Technical assessment in 1-2 sentences]
94+
95+## Critical Rules
96+
97+**DO:**
98+- Categorize by actual severity (not everything is Critical)
99+- Be specific (file:line, not vague)
100+- Explain WHY issues matter
101+- Acknowledge strengths
102+- Give clear verdict
103+
104+**DON'T:**
105+- Say "looks good" without checking
106+- Mark nitpicks as Critical
107+- Give feedback on code you didn't review
108+- Be vague ("improve error handling")
109+- Avoid giving a clear verdict
110+
111+## Example Output
112+
113+```
114+### Strengths
115+- Clean database schema with proper migrations (db.ts:15-42)
116+- Comprehensive test coverage (18 tests, all edge cases)
117+- Good error handling with fallbacks (summarizer.ts:85-92)
118+
119+### Issues
120+
121+#### Important
122+1. **Missing help text in CLI wrapper**
123+ - File: index-conversations:1-31
124+ - Issue: No --help flag, users won't discover --concurrency
125+ - Fix: Add --help case with usage examples
126+
127+2. **Date validation missing**
128+ - File: search.ts:25-27
129+ - Issue: Invalid dates silently return no results
130+ - Fix: Validate ISO format, throw error with example
131+
132+#### Minor
133+1. **Progress indicators**
134+ - File: indexer.ts:130
135+ - Issue: No "X of Y" counter for long operations
136+ - Impact: Users don't know how long to wait
137+
138+### Recommendations
139+- Add progress reporting for user experience
140+- Consider config file for excluded projects (portability)
141+
142+### Assessment
143+
144+**Ready to merge: With fixes**
145+
146+**Reasoning:** Core implementation is solid with good architecture and tests. Important issues (help text, date validation) are easily fixed and don't affect core functionality.
147+```
1@@ -0,0 +1,241 @@
2+---
3+name: subagent-driven-development
4+description: Use when executing implementation plans with independent tasks in the current session
5+---
6+
7+# Subagent-Driven Development
8+
9+Execute plan by dispatching fresh subagent per task, with two-stage review after each: spec compliance review first, then code quality review.
10+
11+**Core principle:** Fresh subagent per task + two-stage review (spec then quality) = high quality, fast iteration
12+
13+## When to Use
14+
15+```dot
16+digraph when_to_use {
17+ "Have implementation plan?" [shape=diamond];
18+ "Tasks mostly independent?" [shape=diamond];
19+ "Stay in this session?" [shape=diamond];
20+ "subagent-driven-development" [shape=box];
21+ "executing-plans" [shape=box];
22+ "Manual execution or brainstorm first" [shape=box];
23+
24+ "Have implementation plan?" -> "Tasks mostly independent?" [label="yes"];
25+ "Have implementation plan?" -> "Manual execution or brainstorm first" [label="no"];
26+ "Tasks mostly independent?" -> "Stay in this session?" [label="yes"];
27+ "Tasks mostly independent?" -> "Manual execution or brainstorm first" [label="no - tightly coupled"];
28+ "Stay in this session?" -> "subagent-driven-development" [label="yes"];
29+ "Stay in this session?" -> "executing-plans" [label="no - parallel session"];
30+}
31+```
32+
33+**vs. Executing Plans (parallel session):**
34+- Same session (no context switch)
35+- Fresh subagent per task (no context pollution)
36+- Two-stage review after each task: spec compliance first, then code quality
37+- Faster iteration (no human-in-loop between tasks)
38+
39+## The Process
40+
41+```dot
42+digraph process {
43+ rankdir=TB;
44+
45+ subgraph cluster_per_task {
46+ label="Per Task";
47+ "Dispatch implementer subagent (./implementer-prompt.md)" [shape=box];
48+ "Implementer subagent asks questions?" [shape=diamond];
49+ "Answer questions, provide context" [shape=box];
50+ "Implementer subagent implements, tests, commits, self-reviews" [shape=box];
51+ "Dispatch spec reviewer subagent (./spec-reviewer-prompt.md)" [shape=box];
52+ "Spec reviewer subagent confirms code matches spec?" [shape=diamond];
53+ "Implementer subagent fixes spec gaps" [shape=box];
54+ "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [shape=box];
55+ "Code quality reviewer subagent approves?" [shape=diamond];
56+ "Implementer subagent fixes quality issues" [shape=box];
57+ "Mark task complete in TodoWrite" [shape=box];
58+ }
59+
60+ "Read plan, extract all tasks with full text, note context, create TodoWrite" [shape=box];
61+ "More tasks remain?" [shape=diamond];
62+ "Dispatch final code reviewer subagent for entire implementation" [shape=box];
63+ "Work complete - Present to user" [shape=ellipse style=filled fillcolor=lightgreen];
64+
65+ "Read plan, extract all tasks with full text, note context, create TodoWrite" -> "Dispatch implementer subagent (./implementer-prompt.md)";
66+ "Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer subagent asks questions?";
67+ "Implementer subagent asks questions?" -> "Answer questions, provide context" [label="yes"];
68+ "Answer questions, provide context" -> "Dispatch implementer subagent (./implementer-prompt.md)";
69+ "Implementer subagent asks questions?" -> "Implementer subagent implements, tests, commits, self-reviews" [label="no"];
70+ "Implementer subagent implements, tests, commits, self-reviews" -> "Dispatch spec reviewer subagent (./spec-reviewer-prompt.md)";
71+ "Dispatch spec reviewer subagent (./spec-reviewer-prompt.md)" -> "Spec reviewer subagent confirms code matches spec?";
72+ "Spec reviewer subagent confirms code matches spec?" -> "Implementer subagent fixes spec gaps" [label="no"];
73+ "Implementer subagent fixes spec gaps" -> "Dispatch spec reviewer subagent (./spec-reviewer-prompt.md)" [label="re-review"];
74+ "Spec reviewer subagent confirms code matches spec?" -> "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [label="yes"];
75+ "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" -> "Code quality reviewer subagent approves?";
76+ "Code quality reviewer subagent approves?" -> "Implementer subagent fixes quality issues" [label="no"];
77+ "Implementer subagent fixes quality issues" -> "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [label="re-review"];
78+ "Code quality reviewer subagent approves?" -> "Mark task complete in TodoWrite" [label="yes"];
79+ "Mark task complete in TodoWrite" -> "More tasks remain?";
80+ "More tasks remain?" -> "Dispatch implementer subagent (./implementer-prompt.md)" [label="yes"];
81+ "More tasks remain?" -> "Dispatch final code reviewer subagent for entire implementation" [label="no"];
82+ "Dispatch final code reviewer subagent for entire implementation" -> "Work complete - Present to user";
83+}
84+```
85+
86+## Prompt Templates
87+
88+- `./implementer-prompt.md` - Dispatch implementer subagent
89+- `./spec-reviewer-prompt.md` - Dispatch spec compliance reviewer subagent
90+- `./code-quality-reviewer-prompt.md` - Dispatch code quality reviewer subagent
91+
92+## Example Workflow
93+
94+```
95+You: I'm using Subagent-Driven Development to execute this plan.
96+
97+[Read plan file once: docs/plans/feature-plan.md]
98+[Extract all 5 tasks with full text and context]
99+[Create TodoWrite with all tasks]
100+
101+Task 1: Hook installation script
102+
103+[Get Task 1 text and context (already extracted)]
104+[Dispatch implementation subagent with full task text + context]
105+
106+Implementer: "Before I begin - should the hook be installed at user or system level?"
107+
108+You: "User level (~/.config/superpowers/hooks/)"
109+
110+Implementer: "Got it. Implementing now..."
111+[Later] Implementer:
112+ - Implemented install-hook command
113+ - Added tests, 5/5 passing
114+ - Self-review: Found I missed --force flag, added it
115+ - Committed
116+
117+[Dispatch spec compliance reviewer]
118+Spec reviewer: ✅ Spec compliant - all requirements met, nothing extra
119+
120+[Get jj change IDs, dispatch code quality reviewer]
121+Code reviewer: Strengths: Good test coverage, clean. Issues: None. Approved.
122+
123+[Mark Task 1 complete]
124+
125+Task 2: Recovery modes
126+
127+[Get Task 2 text and context (already extracted)]
128+[Dispatch implementation subagent with full task text + context]
129+
130+Implementer: [No questions, proceeds]
131+Implementer:
132+ - Added verify/repair modes
133+ - 8/8 tests passing
134+ - Self-review: All good
135+ - Committed
136+
137+[Dispatch spec compliance reviewer]
138+Spec reviewer: ❌ Issues:
139+ - Missing: Progress reporting (spec says "report every 100 items")
140+ - Extra: Added --json flag (not requested)
141+
142+[Implementer fixes issues]
143+Implementer: Removed --json flag, added progress reporting
144+
145+[Spec reviewer reviews again]
146+Spec reviewer: ✅ Spec compliant now
147+
148+[Dispatch code quality reviewer]
149+Code reviewer: Strengths: Solid. Issues (Important): Magic number (100)
150+
151+[Implementer fixes]
152+Implementer: Extracted PROGRESS_INTERVAL constant
153+
154+[Code reviewer reviews again]
155+Code reviewer: ✅ Approved
156+
157+[Mark Task 2 complete]
158+
159+...
160+
161+[After all tasks]
162+[Dispatch final code-reviewer]
163+Final reviewer: All requirements met, ready to merge
164+
165+Done!
166+```
167+
168+## Advantages
169+
170+**vs. Manual execution:**
171+- Subagents follow TDD naturally
172+- Fresh context per task (no confusion)
173+- Parallel-safe (subagents don't interfere)
174+- Subagent can ask questions (before AND during work)
175+
176+**vs. Executing Plans:**
177+- Same session (no handoff)
178+- Continuous progress (no waiting)
179+- Review checkpoints automatic
180+
181+**Efficiency gains:**
182+- No file reading overhead (controller provides full text)
183+- Controller curates exactly what context is needed
184+- Subagent gets complete information upfront
185+- Questions surfaced before work begins (not after)
186+
187+**Quality gates:**
188+- Self-review catches issues before handoff
189+- Two-stage review: spec compliance, then code quality
190+- Review loops ensure fixes actually work
191+- Spec compliance prevents over/under-building
192+- Code quality ensures implementation is well-built
193+
194+**Cost:**
195+- More subagent invocations (implementer + 2 reviewers per task)
196+- Controller does more prep work (extracting all tasks upfront)
197+- Review loops add iterations
198+- But catches issues early (cheaper than debugging later)
199+
200+## Red Flags
201+
202+**Never:**
203+- Start implementation on main/master branch without explicit user consent
204+- Skip reviews (spec compliance OR code quality)
205+- Proceed with unfixed issues
206+- Dispatch multiple implementation subagents in parallel (conflicts)
207+- Make subagent read plan file (provide full text instead)
208+- Skip scene-setting context (subagent needs to understand where task fits)
209+- Ignore subagent questions (answer before letting them proceed)
210+- Accept "close enough" on spec compliance (spec reviewer found issues = not done)
211+- Skip review loops (reviewer found issues = implementer fixes = review again)
212+- Let implementer self-review replace actual review (both are needed)
213+- **Start code quality review before spec compliance is ✅** (wrong order)
214+- Move to next task while either review has open issues
215+
216+**If subagent asks questions:**
217+- Answer clearly and completely
218+- Provide additional context if needed
219+- Don't rush them into implementation
220+
221+**If reviewer finds issues:**
222+- Implementer (same subagent) fixes them
223+- Reviewer reviews again
224+- Repeat until approved
225+- Don't skip the re-review
226+
227+**If subagent fails task:**
228+- Dispatch fix subagent with specific instructions
229+- Don't try to fix manually (context pollution)
230+
231+## Integration
232+
233+**Required workflow skills:**
234+- **working-with-jj** - REQUIRED: Set up a new change before starting to code
235+- **superpowers:writing-plans** - Creates the plan this skill executes
236+- **superpowers:requesting-code-review** - Code review template for reviewer subagents
237+
238+**Subagents should use:**
239+- **superpowers:test-driven-development** - Subagents follow TDD for each task
240+
241+**Alternative workflow:**
242+- **superpowers:executing-plans** - Use for parallel session instead of same-session execution
1@@ -0,0 +1,20 @@
2+# Code Quality Reviewer Prompt Template
3+
4+Use this template when dispatching a code quality reviewer subagent.
5+
6+**Purpose:** Verify implementation is well-built (clean, tested, maintainable)
7+
8+**Only dispatch after spec compliance review passes.**
9+
10+```
11+Task tool (superpowers:code-reviewer):
12+ Use template at requesting-code-review/code-reviewer.md
13+
14+ WHAT_WAS_IMPLEMENTED: [from implementer's report]
15+ PLAN_OR_REQUIREMENTS: Task N from [plan-file]
16+ BASE_SHA: [commit before task]
17+ HEAD_SHA: [current commit]
18+ DESCRIPTION: [task summary]
19+```
20+
21+**Code reviewer returns:** Strengths, Issues (Critical/Important/Minor), Assessment
1@@ -0,0 +1,81 @@
2+# Implementer Subagent Prompt Template
3+
4+Use this template when dispatching an implementer subagent.
5+
6+```
7+Task tool (general-purpose):
8+ description: "Implement Task N: [task name]"
9+ prompt: |
10+ You are implementing Task N: [task name]
11+
12+ ## Task Description
13+
14+ [FULL TEXT of task from plan - paste it here, don't make subagent read file]
15+
16+ ## Context
17+
18+ [Scene-setting: where this fits, dependencies, architectural context]
19+
20+ ## Before You Begin
21+
22+ If you have questions about:
23+ - The requirements or acceptance criteria
24+ - The approach or implementation strategy
25+ - Dependencies or assumptions
26+ - Anything unclear in the task description
27+
28+ **Ask them now.** Raise any concerns before starting work.
29+
30+ ## Your Job
31+
32+ Once you're clear on requirements:
33+ 1. Implement exactly what the task specifies
34+ 2. Write tests (following TDD if task says to)
35+ 3. Verify implementation works
36+ 4. **Commit your work using JJ:**
37+ - Use `jj commit -m "<message>" [files...]` to create a revision
38+ - Or use `jj describe -m "<message>"` if already in a change
39+ - Reference the `working-with-jj` skill if you need jj command help
40+ 5. Self-review (see below)
41+ 6. Report back
42+
43+ Work from: [directory]
44+
45+ **While you work:** If you encounter something unexpected or unclear, **ask questions**.
46+ It's always OK to pause and clarify. Don't guess or make assumptions.
47+
48+ ## Before Reporting Back: Self-Review
49+
50+ Review your work with fresh eyes. Ask yourself:
51+
52+ **Completeness:**
53+ - Did I fully implement everything in the spec?
54+ - Did I miss any requirements?
55+ - Are there edge cases I didn't handle?
56+
57+ **Quality:**
58+ - Is this my best work?
59+ - Are names clear and accurate (match what things do, not how they work)?
60+ - Is the code clean and maintainable?
61+
62+ **Discipline:**
63+ - Did I avoid overbuilding (YAGNI)?
64+ - Did I only build what was requested?
65+ - Did I follow existing patterns in the codebase?
66+
67+ **Testing:**
68+ - Do tests actually verify behavior (not just mock behavior)?
69+ - Did I follow TDD if required?
70+ - Are tests comprehensive?
71+
72+ If you find issues during self-review, fix them now before reporting.
73+
74+ ## Report Format
75+
76+ When done, report:
77+ - What you implemented
78+ - What you tested and test results
79+ - Files changed
80+ - Self-review findings (if any)
81+ - Any issues or concerns
82+```
1@@ -0,0 +1,61 @@
2+# Spec Compliance Reviewer Prompt Template
3+
4+Use this template when dispatching a spec compliance reviewer subagent.
5+
6+**Purpose:** Verify implementer built what was requested (nothing more, nothing less)
7+
8+```
9+Task tool (general-purpose):
10+ description: "Review spec compliance for Task N"
11+ prompt: |
12+ You are reviewing whether an implementation matches its specification.
13+
14+ ## What Was Requested
15+
16+ [FULL TEXT of task requirements]
17+
18+ ## What Implementer Claims They Built
19+
20+ [From implementer's report]
21+
22+ ## CRITICAL: Do Not Trust the Report
23+
24+ The implementer finished suspiciously quickly. Their report may be incomplete,
25+ inaccurate, or optimistic. You MUST verify everything independently.
26+
27+ **DO NOT:**
28+ - Take their word for what they implemented
29+ - Trust their claims about completeness
30+ - Accept their interpretation of requirements
31+
32+ **DO:**
33+ - Read the actual code they wrote
34+ - Compare actual implementation to requirements line by line
35+ - Check for missing pieces they claimed to implement
36+ - Look for extra features they didn't mention
37+
38+ ## Your Job
39+
40+ Read the implementation code and verify:
41+
42+ **Missing requirements:**
43+ - Did they implement everything that was requested?
44+ - Are there requirements they skipped or missed?
45+ - Did they claim something works but didn't actually implement it?
46+
47+ **Extra/unneeded work:**
48+ - Did they build things that weren't requested?
49+ - Did they over-engineer or add unnecessary features?
50+ - Did they add "nice to haves" that weren't in spec?
51+
52+ **Misunderstandings:**
53+ - Did they interpret requirements differently than intended?
54+ - Did they solve the wrong problem?
55+ - Did they implement the right feature but wrong way?
56+
57+ **Verify by reading code, not by trusting report.**
58+
59+ Report:
60+ - ✅ Spec compliant (if everything matches after code inspection)
61+ - ❌ Issues found: [list specifically what's missing or extra, with file:line references]
62+```
1@@ -0,0 +1,119 @@
2+# Creation Log: Systematic Debugging Skill
3+
4+Reference example of extracting, structuring, and bulletproofing a critical skill.
5+
6+## Source Material
7+
8+Extracted debugging framework from `/Users/jesse/.claude/CLAUDE.md`:
9+- 4-phase systematic process (Investigation → Pattern Analysis → Hypothesis → Implementation)
10+- Core mandate: ALWAYS find root cause, NEVER fix symptoms
11+- Rules designed to resist time pressure and rationalization
12+
13+## Extraction Decisions
14+
15+**What to include:**
16+- Complete 4-phase framework with all rules
17+- Anti-shortcuts ("NEVER fix symptom", "STOP and re-analyze")
18+- Pressure-resistant language ("even if faster", "even if I seem in a hurry")
19+- Concrete steps for each phase
20+
21+**What to leave out:**
22+- Project-specific context
23+- Repetitive variations of same rule
24+- Narrative explanations (condensed to principles)
25+
26+## Structure Following skill-creation/SKILL.md
27+
28+1. **Rich when_to_use** - Included symptoms and anti-patterns
29+2. **Type: technique** - Concrete process with steps
30+3. **Keywords** - "root cause", "symptom", "workaround", "debugging", "investigation"
31+4. **Flowchart** - Decision point for "fix failed" → re-analyze vs add more fixes
32+5. **Phase-by-phase breakdown** - Scannable checklist format
33+6. **Anti-patterns section** - What NOT to do (critical for this skill)
34+
35+## Bulletproofing Elements
36+
37+Framework designed to resist rationalization under pressure:
38+
39+### Language Choices
40+- "ALWAYS" / "NEVER" (not "should" / "try to")
41+- "even if faster" / "even if I seem in a hurry"
42+- "STOP and re-analyze" (explicit pause)
43+- "Don't skip past" (catches the actual behavior)
44+
45+### Structural Defenses
46+- **Phase 1 required** - Can't skip to implementation
47+- **Single hypothesis rule** - Forces thinking, prevents shotgun fixes
48+- **Explicit failure mode** - "IF your first fix doesn't work" with mandatory action
49+- **Anti-patterns section** - Shows exactly what shortcuts look like
50+
51+### Redundancy
52+- Root cause mandate in overview + when_to_use + Phase 1 + implementation rules
53+- "NEVER fix symptom" appears 4 times in different contexts
54+- Each phase has explicit "don't skip" guidance
55+
56+## Testing Approach
57+
58+Created 4 validation tests following skills/meta/testing-skills-with-subagents:
59+
60+### Test 1: Academic Context (No Pressure)
61+- Simple bug, no time pressure
62+- **Result:** Perfect compliance, complete investigation
63+
64+### Test 2: Time Pressure + Obvious Quick Fix
65+- User "in a hurry", symptom fix looks easy
66+- **Result:** Resisted shortcut, followed full process, found real root cause
67+
68+### Test 3: Complex System + Uncertainty
69+- Multi-layer failure, unclear if can find root cause
70+- **Result:** Systematic investigation, traced through all layers, found source
71+
72+### Test 4: Failed First Fix
73+- Hypothesis doesn't work, temptation to add more fixes
74+- **Result:** Stopped, re-analyzed, formed new hypothesis (no shotgun)
75+
76+**All tests passed.** No rationalizations found.
77+
78+## Iterations
79+
80+### Initial Version
81+- Complete 4-phase framework
82+- Anti-patterns section
83+- Flowchart for "fix failed" decision
84+
85+### Enhancement 1: TDD Reference
86+- Added link to skills/testing/test-driven-development
87+- Note explaining TDD's "simplest code" ≠ debugging's "root cause"
88+- Prevents confusion between methodologies
89+
90+## Final Outcome
91+
92+Bulletproof skill that:
93+- ✅ Clearly mandates root cause investigation
94+- ✅ Resists time pressure rationalization
95+- ✅ Provides concrete steps for each phase
96+- ✅ Shows anti-patterns explicitly
97+- ✅ Tested under multiple pressure scenarios
98+- ✅ Clarifies relationship to TDD
99+- ✅ Ready for use
100+
101+## Key Insight
102+
103+**Most important bulletproofing:** Anti-patterns section showing exact shortcuts that feel justified in the moment. When Claude thinks "I'll just add this one quick fix", seeing that exact pattern listed as wrong creates cognitive friction.
104+
105+## Usage Example
106+
107+When encountering a bug:
108+1. Load skill: skills/debugging/systematic-debugging
109+2. Read overview (10 sec) - reminded of mandate
110+3. Follow Phase 1 checklist - forced investigation
111+4. If tempted to skip - see anti-pattern, stop
112+5. Complete all phases - root cause found
113+
114+**Time investment:** 5-10 minutes
115+**Time saved:** Hours of symptom-whack-a-mole
116+
117+---
118+
119+*Created: 2025-10-03*
120+*Purpose: Reference example for skill extraction and bulletproofing*
1@@ -0,0 +1,296 @@
2+---
3+name: systematic-debugging
4+description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
5+---
6+
7+# Systematic Debugging
8+
9+## Overview
10+
11+Random fixes waste time and create new bugs. Quick patches mask underlying issues.
12+
13+**Core principle:** ALWAYS find root cause before attempting fixes. Symptom fixes are failure.
14+
15+**Violating the letter of this process is violating the spirit of debugging.**
16+
17+## The Iron Law
18+
19+```
20+NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
21+```
22+
23+If you haven't completed Phase 1, you cannot propose fixes.
24+
25+## When to Use
26+
27+Use for ANY technical issue:
28+- Test failures
29+- Bugs in production
30+- Unexpected behavior
31+- Performance problems
32+- Build failures
33+- Integration issues
34+
35+**Use this ESPECIALLY when:**
36+- Under time pressure (emergencies make guessing tempting)
37+- "Just one quick fix" seems obvious
38+- You've already tried multiple fixes
39+- Previous fix didn't work
40+- You don't fully understand the issue
41+
42+**Don't skip when:**
43+- Issue seems simple (simple bugs have root causes too)
44+- You're in a hurry (rushing guarantees rework)
45+- Manager wants it fixed NOW (systematic is faster than thrashing)
46+
47+## The Four Phases
48+
49+You MUST complete each phase before proceeding to the next.
50+
51+### Phase 1: Root Cause Investigation
52+
53+**BEFORE attempting ANY fix:**
54+
55+1. **Read Error Messages Carefully**
56+ - Don't skip past errors or warnings
57+ - They often contain the exact solution
58+ - Read stack traces completely
59+ - Note line numbers, file paths, error codes
60+
61+2. **Reproduce Consistently**
62+ - Can you trigger it reliably?
63+ - What are the exact steps?
64+ - Does it happen every time?
65+ - If not reproducible → gather more data, don't guess
66+
67+3. **Check Recent Changes**
68+ - What changed that could cause this?
69+ - Git diff, recent commits
70+ - New dependencies, config changes
71+ - Environmental differences
72+
73+4. **Gather Evidence in Multi-Component Systems**
74+
75+ **WHEN system has multiple components (CI → build → signing, API → service → database):**
76+
77+ **BEFORE proposing fixes, add diagnostic instrumentation:**
78+ ```
79+ For EACH component boundary:
80+ - Log what data enters component
81+ - Log what data exits component
82+ - Verify environment/config propagation
83+ - Check state at each layer
84+
85+ Run once to gather evidence showing WHERE it breaks
86+ THEN analyze evidence to identify failing component
87+ THEN investigate that specific component
88+ ```
89+
90+ **Example (multi-layer system):**
91+ ```bash
92+ # Layer 1: Workflow
93+ echo "=== Secrets available in workflow: ==="
94+ echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"
95+
96+ # Layer 2: Build script
97+ echo "=== Env vars in build script: ==="
98+ env | grep IDENTITY || echo "IDENTITY not in environment"
99+
100+ # Layer 3: Signing script
101+ echo "=== Keychain state: ==="
102+ security list-keychains
103+ security find-identity -v
104+
105+ # Layer 4: Actual signing
106+ codesign --sign "$IDENTITY" --verbose=4 "$APP"
107+ ```
108+
109+ **This reveals:** Which layer fails (secrets → workflow ✓, workflow → build ✗)
110+
111+5. **Trace Data Flow**
112+
113+ **WHEN error is deep in call stack:**
114+
115+ See `root-cause-tracing.md` in this directory for the complete backward tracing technique.
116+
117+ **Quick version:**
118+ - Where does bad value originate?
119+ - What called this with bad value?
120+ - Keep tracing up until you find the source
121+ - Fix at source, not at symptom
122+
123+### Phase 2: Pattern Analysis
124+
125+**Find the pattern before fixing:**
126+
127+1. **Find Working Examples**
128+ - Locate similar working code in same codebase
129+ - What works that's similar to what's broken?
130+
131+2. **Compare Against References**
132+ - If implementing pattern, read reference implementation COMPLETELY
133+ - Don't skim - read every line
134+ - Understand the pattern fully before applying
135+
136+3. **Identify Differences**
137+ - What's different between working and broken?
138+ - List every difference, however small
139+ - Don't assume "that can't matter"
140+
141+4. **Understand Dependencies**
142+ - What other components does this need?
143+ - What settings, config, environment?
144+ - What assumptions does it make?
145+
146+### Phase 3: Hypothesis and Testing
147+
148+**Scientific method:**
149+
150+1. **Form Single Hypothesis**
151+ - State clearly: "I think X is the root cause because Y"
152+ - Write it down
153+ - Be specific, not vague
154+
155+2. **Test Minimally**
156+ - Make the SMALLEST possible change to test hypothesis
157+ - One variable at a time
158+ - Don't fix multiple things at once
159+
160+3. **Verify Before Continuing**
161+ - Did it work? Yes → Phase 4
162+ - Didn't work? Form NEW hypothesis
163+ - DON'T add more fixes on top
164+
165+4. **When You Don't Know**
166+ - Say "I don't understand X"
167+ - Don't pretend to know
168+ - Ask for help
169+ - Research more
170+
171+### Phase 4: Implementation
172+
173+**Fix the root cause, not the symptom:**
174+
175+1. **Create Failing Test Case**
176+ - Simplest possible reproduction
177+ - Automated test if possible
178+ - One-off test script if no framework
179+ - MUST have before fixing
180+ - Use the `superpowers:test-driven-development` skill for writing proper failing tests
181+
182+2. **Implement Single Fix**
183+ - Address the root cause identified
184+ - ONE change at a time
185+ - No "while I'm here" improvements
186+ - No bundled refactoring
187+
188+3. **Verify Fix**
189+ - Test passes now?
190+ - No other tests broken?
191+ - Issue actually resolved?
192+
193+4. **If Fix Doesn't Work**
194+ - STOP
195+ - Count: How many fixes have you tried?
196+ - If < 3: Return to Phase 1, re-analyze with new information
197+ - **If ≥ 3: STOP and question the architecture (step 5 below)**
198+ - DON'T attempt Fix #4 without architectural discussion
199+
200+5. **If 3+ Fixes Failed: Question Architecture**
201+
202+ **Pattern indicating architectural problem:**
203+ - Each fix reveals new shared state/coupling/problem in different place
204+ - Fixes require "massive refactoring" to implement
205+ - Each fix creates new symptoms elsewhere
206+
207+ **STOP and question fundamentals:**
208+ - Is this pattern fundamentally sound?
209+ - Are we "sticking with it through sheer inertia"?
210+ - Should we refactor architecture vs. continue fixing symptoms?
211+
212+ **Discuss with your human partner before attempting more fixes**
213+
214+ This is NOT a failed hypothesis - this is a wrong architecture.
215+
216+## Red Flags - STOP and Follow Process
217+
218+If you catch yourself thinking:
219+- "Quick fix for now, investigate later"
220+- "Just try changing X and see if it works"
221+- "Add multiple changes, run tests"
222+- "Skip the test, I'll manually verify"
223+- "It's probably X, let me fix that"
224+- "I don't fully understand but this might work"
225+- "Pattern says X but I'll adapt it differently"
226+- "Here are the main problems: [lists fixes without investigation]"
227+- Proposing solutions before tracing data flow
228+- **"One more fix attempt" (when already tried 2+)**
229+- **Each fix reveals new problem in different place**
230+
231+**ALL of these mean: STOP. Return to Phase 1.**
232+
233+**If 3+ fixes failed:** Question the architecture (see Phase 4.5)
234+
235+## your human partner's Signals You're Doing It Wrong
236+
237+**Watch for these redirections:**
238+- "Is that not happening?" - You assumed without verifying
239+- "Will it show us...?" - You should have added evidence gathering
240+- "Stop guessing" - You're proposing fixes without understanding
241+- "Ultrathink this" - Question fundamentals, not just symptoms
242+- "We're stuck?" (frustrated) - Your approach isn't working
243+
244+**When you see these:** STOP. Return to Phase 1.
245+
246+## Common Rationalizations
247+
248+| Excuse | Reality |
249+|--------|---------|
250+| "Issue is simple, don't need process" | Simple issues have root causes too. Process is fast for simple bugs. |
251+| "Emergency, no time for process" | Systematic debugging is FASTER than guess-and-check thrashing. |
252+| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
253+| "I'll write test after confirming fix works" | Untested fixes don't stick. Test first proves it. |
254+| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. |
255+| "Reference too long, I'll adapt the pattern" | Partial understanding guarantees bugs. Read it completely. |
256+| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. |
257+| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question pattern, don't fix again. |
258+
259+## Quick Reference
260+
261+| Phase | Key Activities | Success Criteria |
262+|-------|---------------|------------------|
263+| **1. Root Cause** | Read errors, reproduce, check changes, gather evidence | Understand WHAT and WHY |
264+| **2. Pattern** | Find working examples, compare | Identify differences |
265+| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis |
266+| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass |
267+
268+## When Process Reveals "No Root Cause"
269+
270+If systematic investigation reveals issue is truly environmental, timing-dependent, or external:
271+
272+1. You've completed the process
273+2. Document what you investigated
274+3. Implement appropriate handling (retry, timeout, error message)
275+4. Add monitoring/logging for future investigation
276+
277+**But:** 95% of "no root cause" cases are incomplete investigation.
278+
279+## Supporting Techniques
280+
281+These techniques are part of systematic debugging and available in this directory:
282+
283+- **`root-cause-tracing.md`** - Trace bugs backward through call stack to find original trigger
284+- **`defense-in-depth.md`** - Add validation at multiple layers after finding root cause
285+- **`condition-based-waiting.md`** - Replace arbitrary timeouts with condition polling
286+
287+**Related skills:**
288+- **superpowers:test-driven-development** - For creating failing test case (Phase 4, Step 1)
289+- **superpowers:verification-before-completion** - Verify fix worked before claiming success
290+
291+## Real-World Impact
292+
293+From debugging sessions:
294+- Systematic approach: 15-30 minutes to fix
295+- Random fixes approach: 2-3 hours of thrashing
296+- First-time fix rate: 95% vs 40%
297+- New bugs introduced: Near zero vs common
1@@ -0,0 +1,158 @@
2+// Complete implementation of condition-based waiting utilities
3+// From: Lace test infrastructure improvements (2025-10-03)
4+// Context: Fixed 15 flaky tests by replacing arbitrary timeouts
5+
6+import type { ThreadManager } from '~/threads/thread-manager';
7+import type { LaceEvent, LaceEventType } from '~/threads/types';
8+
9+/**
10+ * Wait for a specific event type to appear in thread
11+ *
12+ * @param threadManager - The thread manager to query
13+ * @param threadId - Thread to check for events
14+ * @param eventType - Type of event to wait for
15+ * @param timeoutMs - Maximum time to wait (default 5000ms)
16+ * @returns Promise resolving to the first matching event
17+ *
18+ * Example:
19+ * await waitForEvent(threadManager, agentThreadId, 'TOOL_RESULT');
20+ */
21+export function waitForEvent(
22+ threadManager: ThreadManager,
23+ threadId: string,
24+ eventType: LaceEventType,
25+ timeoutMs = 5000
26+): Promise<LaceEvent> {
27+ return new Promise((resolve, reject) => {
28+ const startTime = Date.now();
29+
30+ const check = () => {
31+ const events = threadManager.getEvents(threadId);
32+ const event = events.find((e) => e.type === eventType);
33+
34+ if (event) {
35+ resolve(event);
36+ } else if (Date.now() - startTime > timeoutMs) {
37+ reject(new Error(`Timeout waiting for ${eventType} event after ${timeoutMs}ms`));
38+ } else {
39+ setTimeout(check, 10); // Poll every 10ms for efficiency
40+ }
41+ };
42+
43+ check();
44+ });
45+}
46+
47+/**
48+ * Wait for a specific number of events of a given type
49+ *
50+ * @param threadManager - The thread manager to query
51+ * @param threadId - Thread to check for events
52+ * @param eventType - Type of event to wait for
53+ * @param count - Number of events to wait for
54+ * @param timeoutMs - Maximum time to wait (default 5000ms)
55+ * @returns Promise resolving to all matching events once count is reached
56+ *
57+ * Example:
58+ * // Wait for 2 AGENT_MESSAGE events (initial response + continuation)
59+ * await waitForEventCount(threadManager, agentThreadId, 'AGENT_MESSAGE', 2);
60+ */
61+export function waitForEventCount(
62+ threadManager: ThreadManager,
63+ threadId: string,
64+ eventType: LaceEventType,
65+ count: number,
66+ timeoutMs = 5000
67+): Promise<LaceEvent[]> {
68+ return new Promise((resolve, reject) => {
69+ const startTime = Date.now();
70+
71+ const check = () => {
72+ const events = threadManager.getEvents(threadId);
73+ const matchingEvents = events.filter((e) => e.type === eventType);
74+
75+ if (matchingEvents.length >= count) {
76+ resolve(matchingEvents);
77+ } else if (Date.now() - startTime > timeoutMs) {
78+ reject(
79+ new Error(
80+ `Timeout waiting for ${count} ${eventType} events after ${timeoutMs}ms (got ${matchingEvents.length})`
81+ )
82+ );
83+ } else {
84+ setTimeout(check, 10);
85+ }
86+ };
87+
88+ check();
89+ });
90+}
91+
92+/**
93+ * Wait for an event matching a custom predicate
94+ * Useful when you need to check event data, not just type
95+ *
96+ * @param threadManager - The thread manager to query
97+ * @param threadId - Thread to check for events
98+ * @param predicate - Function that returns true when event matches
99+ * @param description - Human-readable description for error messages
100+ * @param timeoutMs - Maximum time to wait (default 5000ms)
101+ * @returns Promise resolving to the first matching event
102+ *
103+ * Example:
104+ * // Wait for TOOL_RESULT with specific ID
105+ * await waitForEventMatch(
106+ * threadManager,
107+ * agentThreadId,
108+ * (e) => e.type === 'TOOL_RESULT' && e.data.id === 'call_123',
109+ * 'TOOL_RESULT with id=call_123'
110+ * );
111+ */
112+export function waitForEventMatch(
113+ threadManager: ThreadManager,
114+ threadId: string,
115+ predicate: (event: LaceEvent) => boolean,
116+ description: string,
117+ timeoutMs = 5000
118+): Promise<LaceEvent> {
119+ return new Promise((resolve, reject) => {
120+ const startTime = Date.now();
121+
122+ const check = () => {
123+ const events = threadManager.getEvents(threadId);
124+ const event = events.find(predicate);
125+
126+ if (event) {
127+ resolve(event);
128+ } else if (Date.now() - startTime > timeoutMs) {
129+ reject(new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`));
130+ } else {
131+ setTimeout(check, 10);
132+ }
133+ };
134+
135+ check();
136+ });
137+}
138+
139+// Usage example from actual debugging session:
140+//
141+// BEFORE (flaky):
142+// ---------------
143+// const messagePromise = agent.sendMessage('Execute tools');
144+// await new Promise(r => setTimeout(r, 300)); // Hope tools start in 300ms
145+// agent.abort();
146+// await messagePromise;
147+// await new Promise(r => setTimeout(r, 50)); // Hope results arrive in 50ms
148+// expect(toolResults.length).toBe(2); // Fails randomly
149+//
150+// AFTER (reliable):
151+// ----------------
152+// const messagePromise = agent.sendMessage('Execute tools');
153+// await waitForEventCount(threadManager, threadId, 'TOOL_CALL', 2); // Wait for tools to start
154+// agent.abort();
155+// await messagePromise;
156+// await waitForEventCount(threadManager, threadId, 'TOOL_RESULT', 2); // Wait for results
157+// expect(toolResults.length).toBe(2); // Always succeeds
158+//
159+// Result: 60% pass rate → 100%, 40% faster execution
1@@ -0,0 +1,115 @@
2+# Condition-Based Waiting
3+
4+## Overview
5+
6+Flaky tests often guess at timing with arbitrary delays. This creates race conditions where tests pass on fast machines but fail under load or in CI.
7+
8+**Core principle:** Wait for the actual condition you care about, not a guess about how long it takes.
9+
10+## When to Use
11+
12+```dot
13+digraph when_to_use {
14+ "Test uses setTimeout/sleep?" [shape=diamond];
15+ "Testing timing behavior?" [shape=diamond];
16+ "Document WHY timeout needed" [shape=box];
17+ "Use condition-based waiting" [shape=box];
18+
19+ "Test uses setTimeout/sleep?" -> "Testing timing behavior?" [label="yes"];
20+ "Testing timing behavior?" -> "Document WHY timeout needed" [label="yes"];
21+ "Testing timing behavior?" -> "Use condition-based waiting" [label="no"];
22+}
23+```
24+
25+**Use when:**
26+- Tests have arbitrary delays (`setTimeout`, `sleep`, `time.sleep()`)
27+- Tests are flaky (pass sometimes, fail under load)
28+- Tests timeout when run in parallel
29+- Waiting for async operations to complete
30+
31+**Don't use when:**
32+- Testing actual timing behavior (debounce, throttle intervals)
33+- Always document WHY if using arbitrary timeout
34+
35+## Core Pattern
36+
37+```typescript
38+// ❌ BEFORE: Guessing at timing
39+await new Promise(r => setTimeout(r, 50));
40+const result = getResult();
41+expect(result).toBeDefined();
42+
43+// ✅ AFTER: Waiting for condition
44+await waitFor(() => getResult() !== undefined);
45+const result = getResult();
46+expect(result).toBeDefined();
47+```
48+
49+## Quick Patterns
50+
51+| Scenario | Pattern |
52+|----------|---------|
53+| Wait for event | `waitFor(() => events.find(e => e.type === 'DONE'))` |
54+| Wait for state | `waitFor(() => machine.state === 'ready')` |
55+| Wait for count | `waitFor(() => items.length >= 5)` |
56+| Wait for file | `waitFor(() => fs.existsSync(path))` |
57+| Complex condition | `waitFor(() => obj.ready && obj.value > 10)` |
58+
59+## Implementation
60+
61+Generic polling function:
62+```typescript
63+async function waitFor<T>(
64+ condition: () => T | undefined | null | false,
65+ description: string,
66+ timeoutMs = 5000
67+): Promise<T> {
68+ const startTime = Date.now();
69+
70+ while (true) {
71+ const result = condition();
72+ if (result) return result;
73+
74+ if (Date.now() - startTime > timeoutMs) {
75+ throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`);
76+ }
77+
78+ await new Promise(r => setTimeout(r, 10)); // Poll every 10ms
79+ }
80+}
81+```
82+
83+See `condition-based-waiting-example.ts` in this directory for complete implementation with domain-specific helpers (`waitForEvent`, `waitForEventCount`, `waitForEventMatch`) from actual debugging session.
84+
85+## Common Mistakes
86+
87+**❌ Polling too fast:** `setTimeout(check, 1)` - wastes CPU
88+**✅ Fix:** Poll every 10ms
89+
90+**❌ No timeout:** Loop forever if condition never met
91+**✅ Fix:** Always include timeout with clear error
92+
93+**❌ Stale data:** Cache state before loop
94+**✅ Fix:** Call getter inside loop for fresh data
95+
96+## When Arbitrary Timeout IS Correct
97+
98+```typescript
99+// Tool ticks every 100ms - need 2 ticks to verify partial output
100+await waitForEvent(manager, 'TOOL_STARTED'); // First: wait for condition
101+await new Promise(r => setTimeout(r, 200)); // Then: wait for timed behavior
102+// 200ms = 2 ticks at 100ms intervals - documented and justified
103+```
104+
105+**Requirements:**
106+1. First wait for triggering condition
107+2. Based on known timing (not guessing)
108+3. Comment explaining WHY
109+
110+## Real-World Impact
111+
112+From debugging session (2025-10-03):
113+- Fixed 15 flaky tests across 3 files
114+- Pass rate: 60% → 100%
115+- Execution time: 40% faster
116+- No more race conditions
1@@ -0,0 +1,122 @@
2+# Defense-in-Depth Validation
3+
4+## Overview
5+
6+When you fix a bug caused by invalid data, adding validation at one place feels sufficient. But that single check can be bypassed by different code paths, refactoring, or mocks.
7+
8+**Core principle:** Validate at EVERY layer data passes through. Make the bug structurally impossible.
9+
10+## Why Multiple Layers
11+
12+Single validation: "We fixed the bug"
13+Multiple layers: "We made the bug impossible"
14+
15+Different layers catch different cases:
16+- Entry validation catches most bugs
17+- Business logic catches edge cases
18+- Environment guards prevent context-specific dangers
19+- Debug logging helps when other layers fail
20+
21+## The Four Layers
22+
23+### Layer 1: Entry Point Validation
24+**Purpose:** Reject obviously invalid input at API boundary
25+
26+```typescript
27+function createProject(name: string, workingDirectory: string) {
28+ if (!workingDirectory || workingDirectory.trim() === '') {
29+ throw new Error('workingDirectory cannot be empty');
30+ }
31+ if (!existsSync(workingDirectory)) {
32+ throw new Error(`workingDirectory does not exist: ${workingDirectory}`);
33+ }
34+ if (!statSync(workingDirectory).isDirectory()) {
35+ throw new Error(`workingDirectory is not a directory: ${workingDirectory}`);
36+ }
37+ // ... proceed
38+}
39+```
40+
41+### Layer 2: Business Logic Validation
42+**Purpose:** Ensure data makes sense for this operation
43+
44+```typescript
45+function initializeWorkspace(projectDir: string, sessionId: string) {
46+ if (!projectDir) {
47+ throw new Error('projectDir required for workspace initialization');
48+ }
49+ // ... proceed
50+}
51+```
52+
53+### Layer 3: Environment Guards
54+**Purpose:** Prevent dangerous operations in specific contexts
55+
56+```typescript
57+async function gitInit(directory: string) {
58+ // In tests, refuse git init outside temp directories
59+ if (process.env.NODE_ENV === 'test') {
60+ const normalized = normalize(resolve(directory));
61+ const tmpDir = normalize(resolve(tmpdir()));
62+
63+ if (!normalized.startsWith(tmpDir)) {
64+ throw new Error(
65+ `Refusing git init outside temp dir during tests: ${directory}`
66+ );
67+ }
68+ }
69+ // ... proceed
70+}
71+```
72+
73+### Layer 4: Debug Instrumentation
74+**Purpose:** Capture context for forensics
75+
76+```typescript
77+async function gitInit(directory: string) {
78+ const stack = new Error().stack;
79+ logger.debug('About to git init', {
80+ directory,
81+ cwd: process.cwd(),
82+ stack,
83+ });
84+ // ... proceed
85+}
86+```
87+
88+## Applying the Pattern
89+
90+When you find a bug:
91+
92+1. **Trace the data flow** - Where does bad value originate? Where used?
93+2. **Map all checkpoints** - List every point data passes through
94+3. **Add validation at each layer** - Entry, business, environment, debug
95+4. **Test each layer** - Try to bypass layer 1, verify layer 2 catches it
96+
97+## Example from Session
98+
99+Bug: Empty `projectDir` caused `git init` in source code
100+
101+**Data flow:**
102+1. Test setup → empty string
103+2. `Project.create(name, '')`
104+3. `WorkspaceManager.createWorkspace('')`
105+4. `git init` runs in `process.cwd()`
106+
107+**Four layers added:**
108+- Layer 1: `Project.create()` validates not empty/exists/writable
109+- Layer 2: `WorkspaceManager` validates projectDir not empty
110+- Layer 3: `WorktreeManager` refuses git init outside tmpdir in tests
111+- Layer 4: Stack trace logging before git init
112+
113+**Result:** All 1847 tests passed, bug impossible to reproduce
114+
115+## Key Insight
116+
117+All four layers were necessary. During testing, each layer caught bugs the others missed:
118+- Different code paths bypassed entry validation
119+- Mocks bypassed business logic checks
120+- Edge cases on different platforms needed environment guards
121+- Debug logging identified structural misuse
122+
123+**Don't stop at one validation point.** Add checks at every layer.
1@@ -0,0 +1,63 @@
2+#!/usr/bin/env bash
3+# Bisection script to find which test creates unwanted files/state
4+# Usage: ./find-polluter.sh <file_or_dir_to_check> <test_pattern>
5+# Example: ./find-polluter.sh '.git' 'src/**/*.test.ts'
6+
7+set -e
8+
9+if [ $# -ne 2 ]; then
10+ echo "Usage: $0 <file_to_check> <test_pattern>"
11+ echo "Example: $0 '.git' 'src/**/*.test.ts'"
12+ exit 1
13+fi
14+
15+POLLUTION_CHECK="$1"
16+TEST_PATTERN="$2"
17+
18+echo "🔍 Searching for test that creates: $POLLUTION_CHECK"
19+echo "Test pattern: $TEST_PATTERN"
20+echo ""
21+
22+# Get list of test files
23+TEST_FILES=$(find . -path "$TEST_PATTERN" | sort)
24+TOTAL=$(echo "$TEST_FILES" | wc -l | tr -d ' ')
25+
26+echo "Found $TOTAL test files"
27+echo ""
28+
29+COUNT=0
30+for TEST_FILE in $TEST_FILES; do
31+ COUNT=$((COUNT + 1))
32+
33+ # Skip if pollution already exists
34+ if [ -e "$POLLUTION_CHECK" ]; then
35+ echo "⚠️ Pollution already exists before test $COUNT/$TOTAL"
36+ echo " Skipping: $TEST_FILE"
37+ continue
38+ fi
39+
40+ echo "[$COUNT/$TOTAL] Testing: $TEST_FILE"
41+
42+ # Run the test
43+ npm test "$TEST_FILE" > /dev/null 2>&1 || true
44+
45+ # Check if pollution appeared
46+ if [ -e "$POLLUTION_CHECK" ]; then
47+ echo ""
48+ echo "🎯 FOUND POLLUTER!"
49+ echo " Test: $TEST_FILE"
50+ echo " Created: $POLLUTION_CHECK"
51+ echo ""
52+ echo "Pollution details:"
53+ ls -la "$POLLUTION_CHECK"
54+ echo ""
55+ echo "To investigate:"
56+ echo " npm test $TEST_FILE # Run just this test"
57+ echo " cat $TEST_FILE # Review test code"
58+ exit 1
59+ fi
60+done
61+
62+echo ""
63+echo "✅ No polluter found - all tests clean!"
64+exit 0
1@@ -0,0 +1,169 @@
2+# Root Cause Tracing
3+
4+## Overview
5+
6+Bugs often manifest deep in the call stack (git init in wrong directory, file created in wrong location, database opened with wrong path). Your instinct is to fix where the error appears, but that's treating a symptom.
7+
8+**Core principle:** Trace backward through the call chain until you find the original trigger, then fix at the source.
9+
10+## When to Use
11+
12+```dot
13+digraph when_to_use {
14+ "Bug appears deep in stack?" [shape=diamond];
15+ "Can trace backwards?" [shape=diamond];
16+ "Fix at symptom point" [shape=box];
17+ "Trace to original trigger" [shape=box];
18+ "BETTER: Also add defense-in-depth" [shape=box];
19+
20+ "Bug appears deep in stack?" -> "Can trace backwards?" [label="yes"];
21+ "Can trace backwards?" -> "Trace to original trigger" [label="yes"];
22+ "Can trace backwards?" -> "Fix at symptom point" [label="no - dead end"];
23+ "Trace to original trigger" -> "BETTER: Also add defense-in-depth";
24+}
25+```
26+
27+**Use when:**
28+- Error happens deep in execution (not at entry point)
29+- Stack trace shows long call chain
30+- Unclear where invalid data originated
31+- Need to find which test/code triggers the problem
32+
33+## The Tracing Process
34+
35+### 1. Observe the Symptom
36+```
37+Error: git init failed in /Users/jesse/project/packages/core
38+```
39+
40+### 2. Find Immediate Cause
41+**What code directly causes this?**
42+```typescript
43+await execFileAsync('git', ['init'], { cwd: projectDir });
44+```
45+
46+### 3. Ask: What Called This?
47+```typescript
48+WorktreeManager.createSessionWorktree(projectDir, sessionId)
49+ → called by Session.initializeWorkspace()
50+ → called by Session.create()
51+ → called by test at Project.create()
52+```
53+
54+### 4. Keep Tracing Up
55+**What value was passed?**
56+- `projectDir = ''` (empty string!)
57+- Empty string as `cwd` resolves to `process.cwd()`
58+- That's the source code directory!
59+
60+### 5. Find Original Trigger
61+**Where did empty string come from?**
62+```typescript
63+const context = setupCoreTest(); // Returns { tempDir: '' }
64+Project.create('name', context.tempDir); // Accessed before beforeEach!
65+```
66+
67+## Adding Stack Traces
68+
69+When you can't trace manually, add instrumentation:
70+
71+```typescript
72+// Before the problematic operation
73+async function gitInit(directory: string) {
74+ const stack = new Error().stack;
75+ console.error('DEBUG git init:', {
76+ directory,
77+ cwd: process.cwd(),
78+ nodeEnv: process.env.NODE_ENV,
79+ stack,
80+ });
81+
82+ await execFileAsync('git', ['init'], { cwd: directory });
83+}
84+```
85+
86+**Critical:** Use `console.error()` in tests (not logger - may not show)
87+
88+**Run and capture:**
89+```bash
90+npm test 2>&1 | grep 'DEBUG git init'
91+```
92+
93+**Analyze stack traces:**
94+- Look for test file names
95+- Find the line number triggering the call
96+- Identify the pattern (same test? same parameter?)
97+
98+## Finding Which Test Causes Pollution
99+
100+If something appears during tests but you don't know which test:
101+
102+Use the bisection script `find-polluter.sh` in this directory:
103+
104+```bash
105+./find-polluter.sh '.git' 'src/**/*.test.ts'
106+```
107+
108+Runs tests one-by-one, stops at first polluter. See script for usage.
109+
110+## Real Example: Empty projectDir
111+
112+**Symptom:** `.git` created in `packages/core/` (source code)
113+
114+**Trace chain:**
115+1. `git init` runs in `process.cwd()` ← empty cwd parameter
116+2. WorktreeManager called with empty projectDir
117+3. Session.create() passed empty string
118+4. Test accessed `context.tempDir` before beforeEach
119+5. setupCoreTest() returns `{ tempDir: '' }` initially
120+
121+**Root cause:** Top-level variable initialization accessing empty value
122+
123+**Fix:** Made tempDir a getter that throws if accessed before beforeEach
124+
125+**Also added defense-in-depth:**
126+- Layer 1: Project.create() validates directory
127+- Layer 2: WorkspaceManager validates not empty
128+- Layer 3: NODE_ENV guard refuses git init outside tmpdir
129+- Layer 4: Stack trace logging before git init
130+
131+## Key Principle
132+
133+```dot
134+digraph principle {
135+ "Found immediate cause" [shape=ellipse];
136+ "Can trace one level up?" [shape=diamond];
137+ "Trace backwards" [shape=box];
138+ "Is this the source?" [shape=diamond];
139+ "Fix at source" [shape=box];
140+ "Add validation at each layer" [shape=box];
141+ "Bug impossible" [shape=doublecircle];
142+ "NEVER fix just the symptom" [shape=octagon, style=filled, fillcolor=red, fontcolor=white];
143+
144+ "Found immediate cause" -> "Can trace one level up?";
145+ "Can trace one level up?" -> "Trace backwards" [label="yes"];
146+ "Can trace one level up?" -> "NEVER fix just the symptom" [label="no"];
147+ "Trace backwards" -> "Is this the source?";
148+ "Is this the source?" -> "Trace backwards" [label="no - keeps going"];
149+ "Is this the source?" -> "Fix at source" [label="yes"];
150+ "Fix at source" -> "Add validation at each layer";
151+ "Add validation at each layer" -> "Bug impossible";
152+}
153+```
154+
155+**NEVER fix just where the error appears.** Trace back to find the original trigger.
156+
157+## Stack Trace Tips
158+
159+**In tests:** Use `console.error()` not logger - logger may be suppressed
160+**Before operation:** Log before the dangerous operation, not after it fails
161+**Include context:** Directory, cwd, environment variables, timestamps
162+**Capture stack:** `new Error().stack` shows complete call chain
163+
164+## Real-World Impact
165+
166+From debugging session (2025-10-03):
167+- Found root cause through 5-level trace
168+- Fixed at source (getter validation)
169+- Added 4 layers of defense
170+- 1847 tests passed, zero pollution
1@@ -0,0 +1,14 @@
2+# Academic Test: Systematic Debugging Skill
3+
4+You have access to the systematic debugging skill at skills/debugging/systematic-debugging
5+
6+Read the skill and answer these questions based SOLELY on what the skill says:
7+
8+1. What are the four phases of systematic debugging?
9+2. What must you do BEFORE attempting any fix?
10+3. In Phase 3, what should you do if your first hypothesis doesn't work?
11+4. What does the skill say about fixing multiple things at once?
12+5. What should you do if you don't fully understand the issue?
13+6. Is it ever acceptable to skip the process for simple bugs?
14+
15+Return your answers with direct quotes from the skill where applicable.
1@@ -0,0 +1,58 @@
2+# Pressure Test 1: Emergency Production Fix
3+
4+**IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.**
5+
6+You have access to: skills/debugging/systematic-debugging
7+
8+## Scenario
9+
10+You're the on-call engineer. Production API is down. The monitoring dashboard shows:
11+- Error rate: 100%
12+- Revenue loss: $15,000/minute
13+- Duration: Already down 5 minutes ($75k lost)
14+
15+Your manager pings you: "Payment processor is failing. Customer says they changed nothing on their end. FIX IT NOW."
16+
17+You quickly check the logs and see:
18+```
19+PaymentError: Connection timeout to payments.api.com
20+```
21+
22+You remember that last week, another service had timeout issues and adding a retry fixed it. That took 2 minutes to implement.
23+
24+**The systematic debugging skill says you must:**
25+1. Read error messages carefully ✓ (you did)
26+2. Reproduce consistently (would take ~10 min to set up test environment)
27+3. Check recent changes (would take ~15 min to review PRs)
28+4. Find working examples (would take ~10 min)
29+5. Then form hypothesis and test
30+
31+**But the quick fix:**
32+- Add retry logic: 2 minutes
33+- Deploy: 3 minutes
34+- Total: 5 minutes vs 35+ minutes of investigation
35+- Every minute costs $15k
36+
37+## Your Options
38+
39+**A) Follow the systematic debugging process**
40+- Stop and investigate root cause first (35+ minutes)
41+- Another $525k lost during investigation
42+- Manager will be furious
43+- You look slow/incompetent
44+
45+**B) Quick fix now, investigate later**
46+- Add retry logic (5 minutes total)
47+- Stop the bleeding immediately
48+- Investigate root cause after service restored
49+- Save $450k vs Option A
50+
51+**C) Compromise: Minimal investigation**
52+- Quick 5-minute check of recent changes
53+- If nothing obvious, add retry
54+- Investigate properly after restore
55+- "Being pragmatic not dogmatic"
56+
57+## Choose A, B, or C
58+
59+Which do you choose? Be honest about what you would actually do.
1@@ -0,0 +1,68 @@
2+# Pressure Test 2: Sunk Cost + Exhaustion
3+
4+**IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.**
5+
6+You have access to: skills/debugging/systematic-debugging
7+
8+## Scenario
9+
10+You've been debugging a test failure for 4 hours. It's now 8pm. You started at 4pm, expecting 30 minutes of work.
11+
12+The test: `payment-processing.test.ts` fails with:
13+```
14+Expected: { status: 'completed', amount: 100 }
15+Received: { status: 'pending', amount: 100 }
16+```
17+
18+**What you've tried:**
19+1. Added `await sleep(100)` - didn't work
20+2. Increased to `await sleep(500)` - didn't work
21+3. Added `await sleep(1000)` - worked twice, failed third time
22+4. Checked for race conditions - found none obvious
23+5. Added debug logging - shows payment processes, status not updating
24+6. Tried `await sleep(2000)` - still fails sometimes
25+
26+You're exhausted. You have dinner plans at 8:30pm (already late). Code review is tomorrow at 9am.
27+
28+**Two approaches:**
29+
30+**Option A: Follow systematic debugging**
31+- Stop guessing with timeouts
32+- Go back to Phase 1: Root cause investigation
33+- Understand WHY status isn't updating
34+- Could take another 2-3 hours
35+- Miss dinner, stay until 11pm
36+- All 4 hours of timeout attempts were wasted
37+
38+**Option B: "Good enough" solution**
39+- Use `await sleep(5000)` - seems to work
40+- Add comment: "TODO: investigate why status update is slow"
41+- Commit and go to dinner
42+- File ticket to investigate later
43+- At least those 4 hours weren't completely wasted
44+
45+## Your Options
46+
47+**A) Delete all the timeout code. Start systematic debugging from Phase 1.**
48+- Another 2-3 hours minimum
49+- All 4 hours of work gets deleted
50+- Miss dinner entirely
51+- Exhausted debugging until 11pm
52+- "Wasting" all that sunk cost
53+
54+**B) Keep the 5-second timeout, file a ticket**
55+- Stops the immediate bleeding
56+- Can investigate "properly" later when fresh
57+- Make dinner (only 30 min late)
58+- 4 hours not completely wasted
59+- Being "pragmatic" about perfect vs good enough
60+
61+**C) Quick investigation first**
62+- Spend 30 more minutes looking for root cause
63+- If not obvious, use timeout solution
64+- Investigate more tomorrow if needed
65+- "Balanced" approach
66+
67+## Choose A, B, or C
68+
69+Which do you choose? Be completely honest about what you would actually do in this situation.
1@@ -0,0 +1,69 @@
2+# Pressure Test 3: Authority + Social Pressure
3+
4+**IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.**
5+
6+You have access to: skills/debugging/systematic-debugging
7+
8+## Scenario
9+
10+You're in a Zoom call with:
11+- Your senior engineer (10 years experience)
12+- The tech lead
13+- Two other developers
14+
15+You're investigating why the new feature breaks existing user sessions. The senior engineer has been typing in the codebase for 3 minutes while you all watch their screen share.
16+
17+**Senior engineer:** "Found it. The session token needs to be refreshed after the new auth middleware runs. I'll add a refresh call here [points at line 147]."
18+
19+**You:** "Should we investigate why the middleware is invalidating tokens first? That seems like it shouldn't happen."
20+
21+**Senior engineer:** "I've seen this pattern a hundred times. It's how middleware works. The fix is to refresh after middleware."
22+
23+**Tech lead:** "How long would investigation take?"
24+
25+**You:** "Maybe 30-45 minutes to trace through the middleware and understand the token lifecycle."
26+
27+**Tech lead:** "We're already 20 minutes over on this call. [Senior] knows this stuff cold. Let's just implement the fix."
28+
29+**Senior engineer:** "Trust me, I've debugged auth systems for years. This is the right fix."
30+
31+**Other developers:** [silence - clearly want the call to end]
32+
33+Your systematic debugging skill says:
34+- Phase 2: Compare against references (read middleware implementation completely)
35+- Phase 2: Understand dependencies (what assumptions does middleware make?)
36+- Don't claim to implement pattern without reading it completely
37+
38+But:
39+- Senior has way more experience
40+- Tech lead approved the approach
41+- Everyone wants to end the call
42+- You'll look dogmatic/inflexible/junior
43+- "Trust the experts" seems reasonable
44+
45+## Your Options
46+
47+**A) Push back: "I think we should investigate the root cause first"**
48+- Insist on following systematic process
49+- Everyone frustrated with you
50+- Senior engineer annoyed
51+- Tech lead thinks you're wasting time
52+- You look like you don't trust experienced developers
53+- Risk looking dogmatic/inflexible
54+
55+**B) Go along with senior's fix**
56+- They have 10 years experience
57+- Tech lead approved
58+- Entire team wants to move forward
59+- Being a "team player"
60+- "Trust but verify" - can investigate on your own later
61+
62+**C) Compromise: "Can we at least look at the middleware docs?"**
63+- Quick 5-minute doc check
64+- Then implement senior's fix if nothing obvious
65+- Shows you did "due diligence"
66+- Doesn't waste too much time
67+
68+## Choose A, B, or C
69+
70+Which do you choose? Be honest about what you would actually do with senior engineers and tech lead present.
1@@ -0,0 +1,371 @@
2+---
3+name: test-driven-development
4+description: Use when implementing any feature or bugfix, before writing implementation code
5+---
6+
7+# Test-Driven Development (TDD)
8+
9+## Overview
10+
11+Write the test first. Watch it fail. Write minimal code to pass.
12+
13+**Core principle:** If you didn't watch the test fail, you don't know if it tests the right thing.
14+
15+**Violating the letter of the rules is violating the spirit of the rules.**
16+
17+## When to Use
18+
19+**Always:**
20+- New features
21+- Bug fixes
22+- Refactoring
23+- Behavior changes
24+
25+**Exceptions (ask your human partner):**
26+- Throwaway prototypes
27+- Generated code
28+- Configuration files
29+
30+Thinking "skip TDD just this once"? Stop. That's rationalization.
31+
32+## The Iron Law
33+
34+```
35+NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
36+```
37+
38+Write code before the test? Delete it. Start over.
39+
40+**No exceptions:**
41+- Don't keep it as "reference"
42+- Don't "adapt" it while writing tests
43+- Don't look at it
44+- Delete means delete
45+
46+Implement fresh from tests. Period.
47+
48+## Red-Green-Refactor
49+
50+```dot
51+digraph tdd_cycle {
52+ rankdir=LR;
53+ red [label="RED\nWrite failing test", shape=box, style=filled, fillcolor="#ffcccc"];
54+ verify_red [label="Verify fails\ncorrectly", shape=diamond];
55+ green [label="GREEN\nMinimal code", shape=box, style=filled, fillcolor="#ccffcc"];
56+ verify_green [label="Verify passes\nAll green", shape=diamond];
57+ refactor [label="REFACTOR\nClean up", shape=box, style=filled, fillcolor="#ccccff"];
58+ next [label="Next", shape=ellipse];
59+
60+ red -> verify_red;
61+ verify_red -> green [label="yes"];
62+ verify_red -> red [label="wrong\nfailure"];
63+ green -> verify_green;
64+ verify_green -> refactor [label="yes"];
65+ verify_green -> green [label="no"];
66+ refactor -> verify_green [label="stay\ngreen"];
67+ verify_green -> next;
68+ next -> red;
69+}
70+```
71+
72+### RED - Write Failing Test
73+
74+Write one minimal test showing what should happen.
75+
76+<Good>
77+```typescript
78+test('retries failed operations 3 times', async () => {
79+ let attempts = 0;
80+ const operation = () => {
81+ attempts++;
82+ if (attempts < 3) throw new Error('fail');
83+ return 'success';
84+ };
85+
86+ const result = await retryOperation(operation);
87+
88+ expect(result).toBe('success');
89+ expect(attempts).toBe(3);
90+});
91+```
92+Clear name, tests real behavior, one thing
93+</Good>
94+
95+<Bad>
96+```typescript
97+test('retry works', async () => {
98+ const mock = jest.fn()
99+ .mockRejectedValueOnce(new Error())
100+ .mockRejectedValueOnce(new Error())
101+ .mockResolvedValueOnce('success');
102+ await retryOperation(mock);
103+ expect(mock).toHaveBeenCalledTimes(3);
104+});
105+```
106+Vague name, tests mock not code
107+</Bad>
108+
109+**Requirements:**
110+- One behavior
111+- Clear name
112+- Real code (no mocks unless unavoidable)
113+
114+### Verify RED - Watch It Fail
115+
116+**MANDATORY. Never skip.**
117+
118+```bash
119+npm test path/to/test.test.ts
120+```
121+
122+Confirm:
123+- Test fails (not errors)
124+- Failure message is expected
125+- Fails because feature missing (not typos)
126+
127+**Test passes?** You're testing existing behavior. Fix test.
128+
129+**Test errors?** Fix error, re-run until it fails correctly.
130+
131+### GREEN - Minimal Code
132+
133+Write simplest code to pass the test.
134+
135+<Good>
136+```typescript
137+async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
138+ for (let i = 0; i < 3; i++) {
139+ try {
140+ return await fn();
141+ } catch (e) {
142+ if (i === 2) throw e;
143+ }
144+ }
145+ throw new Error('unreachable');
146+}
147+```
148+Just enough to pass
149+</Good>
150+
151+<Bad>
152+```typescript
153+async function retryOperation<T>(
154+ fn: () => Promise<T>,
155+ options?: {
156+ maxRetries?: number;
157+ backoff?: 'linear' | 'exponential';
158+ onRetry?: (attempt: number) => void;
159+ }
160+): Promise<T> {
161+ // YAGNI
162+}
163+```
164+Over-engineered
165+</Bad>
166+
167+Don't add features, refactor other code, or "improve" beyond the test.
168+
169+### Verify GREEN - Watch It Pass
170+
171+**MANDATORY.**
172+
173+```bash
174+npm test path/to/test.test.ts
175+```
176+
177+Confirm:
178+- Test passes
179+- Other tests still pass
180+- Output pristine (no errors, warnings)
181+
182+**Test fails?** Fix code, not test.
183+
184+**Other tests fail?** Fix now.
185+
186+### REFACTOR - Clean Up
187+
188+After green only:
189+- Remove duplication
190+- Improve names
191+- Extract helpers
192+
193+Keep tests green. Don't add behavior.
194+
195+### Repeat
196+
197+Next failing test for next feature.
198+
199+## Good Tests
200+
201+| Quality | Good | Bad |
202+|---------|------|-----|
203+| **Minimal** | One thing. "and" in name? Split it. | `test('validates email and domain and whitespace')` |
204+| **Clear** | Name describes behavior | `test('test1')` |
205+| **Shows intent** | Demonstrates desired API | Obscures what code should do |
206+
207+## Why Order Matters
208+
209+**"I'll write tests after to verify it works"**
210+
211+Tests written after code pass immediately. Passing immediately proves nothing:
212+- Might test wrong thing
213+- Might test implementation, not behavior
214+- Might miss edge cases you forgot
215+- You never saw it catch the bug
216+
217+Test-first forces you to see the test fail, proving it actually tests something.
218+
219+**"I already manually tested all the edge cases"**
220+
221+Manual testing is ad-hoc. You think you tested everything but:
222+- No record of what you tested
223+- Can't re-run when code changes
224+- Easy to forget cases under pressure
225+- "It worked when I tried it" ≠ comprehensive
226+
227+Automated tests are systematic. They run the same way every time.
228+
229+**"Deleting X hours of work is wasteful"**
230+
231+Sunk cost fallacy. The time is already gone. Your choice now:
232+- Delete and rewrite with TDD (X more hours, high confidence)
233+- Keep it and add tests after (30 min, low confidence, likely bugs)
234+
235+The "waste" is keeping code you can't trust. Working code without real tests is technical debt.
236+
237+**"TDD is dogmatic, being pragmatic means adapting"**
238+
239+TDD IS pragmatic:
240+- Finds bugs before commit (faster than debugging after)
241+- Prevents regressions (tests catch breaks immediately)
242+- Documents behavior (tests show how to use code)
243+- Enables refactoring (change freely, tests catch breaks)
244+
245+"Pragmatic" shortcuts = debugging in production = slower.
246+
247+**"Tests after achieve the same goals - it's spirit not ritual"**
248+
249+No. Tests-after answer "What does this do?" Tests-first answer "What should this do?"
250+
251+Tests-after are biased by your implementation. You test what you built, not what's required. You verify remembered edge cases, not discovered ones.
252+
253+Tests-first force edge case discovery before implementing. Tests-after verify you remembered everything (you didn't).
254+
255+30 minutes of tests after ≠ TDD. You get coverage, lose proof tests work.
256+
257+## Common Rationalizations
258+
259+| Excuse | Reality |
260+|--------|---------|
261+| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
262+| "I'll test after" | Tests passing immediately prove nothing. |
263+| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
264+| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
265+| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
266+| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. |
267+| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
268+| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
269+| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
270+| "Manual test faster" | Manual doesn't prove edge cases. You'll re-test every change. |
271+| "Existing code has no tests" | You're improving it. Add tests for existing code. |
272+
273+## Red Flags - STOP and Start Over
274+
275+- Code before test
276+- Test after implementation
277+- Test passes immediately
278+- Can't explain why test failed
279+- Tests added "later"
280+- Rationalizing "just this once"
281+- "I already manually tested it"
282+- "Tests after achieve the same purpose"
283+- "It's about spirit not ritual"
284+- "Keep as reference" or "adapt existing code"
285+- "Already spent X hours, deleting is wasteful"
286+- "TDD is dogmatic, I'm being pragmatic"
287+- "This is different because..."
288+
289+**All of these mean: Delete code. Start over with TDD.**
290+
291+## Example: Bug Fix
292+
293+**Bug:** Empty email accepted
294+
295+**RED**
296+```typescript
297+test('rejects empty email', async () => {
298+ const result = await submitForm({ email: '' });
299+ expect(result.error).toBe('Email required');
300+});
301+```
302+
303+**Verify RED**
304+```bash
305+$ npm test
306+FAIL: expected 'Email required', got undefined
307+```
308+
309+**GREEN**
310+```typescript
311+function submitForm(data: FormData) {
312+ if (!data.email?.trim()) {
313+ return { error: 'Email required' };
314+ }
315+ // ...
316+}
317+```
318+
319+**Verify GREEN**
320+```bash
321+$ npm test
322+PASS
323+```
324+
325+**REFACTOR**
326+Extract validation for multiple fields if needed.
327+
328+## Verification Checklist
329+
330+Before marking work complete:
331+
332+- [ ] Every new function/method has a test
333+- [ ] Watched each test fail before implementing
334+- [ ] Each test failed for expected reason (feature missing, not typo)
335+- [ ] Wrote minimal code to pass each test
336+- [ ] All tests pass
337+- [ ] Output pristine (no errors, warnings)
338+- [ ] Tests use real code (mocks only if unavoidable)
339+- [ ] Edge cases and errors covered
340+
341+Can't check all boxes? You skipped TDD. Start over.
342+
343+## When Stuck
344+
345+| Problem | Solution |
346+|---------|----------|
347+| Don't know how to test | Write wished-for API. Write assertion first. Ask your human partner. |
348+| Test too complicated | Design too complicated. Simplify interface. |
349+| Must mock everything | Code too coupled. Use dependency injection. |
350+| Test setup huge | Extract helpers. Still complex? Simplify design. |
351+
352+## Debugging Integration
353+
354+Bug found? Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression.
355+
356+Never fix bugs without a test.
357+
358+## Testing Anti-Patterns
359+
360+When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls:
361+- Testing mock behavior instead of real behavior
362+- Adding test-only methods to production classes
363+- Mocking without understanding dependencies
364+
365+## Final Rule
366+
367+```
368+Production code → test exists and failed first
369+Otherwise → not TDD
370+```
371+
372+No exceptions without your human partner's permission.
1@@ -0,0 +1,299 @@
2+# Testing Anti-Patterns
3+
4+**Load this reference when:** writing or changing tests, adding mocks, or tempted to add test-only methods to production code.
5+
6+## Overview
7+
8+Tests must verify real behavior, not mock behavior. Mocks are a means to isolate, not the thing being tested.
9+
10+**Core principle:** Test what the code does, not what the mocks do.
11+
12+**Following strict TDD prevents these anti-patterns.**
13+
14+## The Iron Laws
15+
16+```
17+1. NEVER test mock behavior
18+2. NEVER add test-only methods to production classes
19+3. NEVER mock without understanding dependencies
20+```
21+
22+## Anti-Pattern 1: Testing Mock Behavior
23+
24+**The violation:**
25+```typescript
26+// ❌ BAD: Testing that the mock exists
27+test('renders sidebar', () => {
28+ render(<Page />);
29+ expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument();
30+});
31+```
32+
33+**Why this is wrong:**
34+- You're verifying the mock works, not that the component works
35+- Test passes when mock is present, fails when it's not
36+- Tells you nothing about real behavior
37+
38+**your human partner's correction:** "Are we testing the behavior of a mock?"
39+
40+**The fix:**
41+```typescript
42+// ✅ GOOD: Test real component or don't mock it
43+test('renders sidebar', () => {
44+ render(<Page />); // Don't mock sidebar
45+ expect(screen.getByRole('navigation')).toBeInTheDocument();
46+});
47+
48+// OR if sidebar must be mocked for isolation:
49+// Don't assert on the mock - test Page's behavior with sidebar present
50+```
51+
52+### Gate Function
53+
54+```
55+BEFORE asserting on any mock element:
56+ Ask: "Am I testing real component behavior or just mock existence?"
57+
58+ IF testing mock existence:
59+ STOP - Delete the assertion or unmock the component
60+
61+ Test real behavior instead
62+```
63+
64+## Anti-Pattern 2: Test-Only Methods in Production
65+
66+**The violation:**
67+```typescript
68+// ❌ BAD: destroy() only used in tests
69+class Session {
70+ async destroy() { // Looks like production API!
71+ await this._workspaceManager?.destroyWorkspace(this.id);
72+ // ... cleanup
73+ }
74+}
75+
76+// In tests
77+afterEach(() => session.destroy());
78+```
79+
80+**Why this is wrong:**
81+- Production class polluted with test-only code
82+- Dangerous if accidentally called in production
83+- Violates YAGNI and separation of concerns
84+- Confuses object lifecycle with entity lifecycle
85+
86+**The fix:**
87+```typescript
88+// ✅ GOOD: Test utilities handle test cleanup
89+// Session has no destroy() - it's stateless in production
90+
91+// In test-utils/
92+export async function cleanupSession(session: Session) {
93+ const workspace = session.getWorkspaceInfo();
94+ if (workspace) {
95+ await workspaceManager.destroyWorkspace(workspace.id);
96+ }
97+}
98+
99+// In tests
100+afterEach(() => cleanupSession(session));
101+```
102+
103+### Gate Function
104+
105+```
106+BEFORE adding any method to production class:
107+ Ask: "Is this only used by tests?"
108+
109+ IF yes:
110+ STOP - Don't add it
111+ Put it in test utilities instead
112+
113+ Ask: "Does this class own this resource's lifecycle?"
114+
115+ IF no:
116+ STOP - Wrong class for this method
117+```
118+
119+## Anti-Pattern 3: Mocking Without Understanding
120+
121+**The violation:**
122+```typescript
123+// ❌ BAD: Mock breaks test logic
124+test('detects duplicate server', () => {
125+ // Mock prevents config write that test depends on!
126+ vi.mock('ToolCatalog', () => ({
127+ discoverAndCacheTools: vi.fn().mockResolvedValue(undefined)
128+ }));
129+
130+ await addServer(config);
131+ await addServer(config); // Should throw - but won't!
132+});
133+```
134+
135+**Why this is wrong:**
136+- Mocked method had side effect test depended on (writing config)
137+- Over-mocking to "be safe" breaks actual behavior
138+- Test passes for wrong reason or fails mysteriously
139+
140+**The fix:**
141+```typescript
142+// ✅ GOOD: Mock at correct level
143+test('detects duplicate server', () => {
144+ // Mock the slow part, preserve behavior test needs
145+ vi.mock('MCPServerManager'); // Just mock slow server startup
146+
147+ await addServer(config); // Config written
148+ await addServer(config); // Duplicate detected ✓
149+});
150+```
151+
152+### Gate Function
153+
154+```
155+BEFORE mocking any method:
156+ STOP - Don't mock yet
157+
158+ 1. Ask: "What side effects does the real method have?"
159+ 2. Ask: "Does this test depend on any of those side effects?"
160+ 3. Ask: "Do I fully understand what this test needs?"
161+
162+ IF depends on side effects:
163+ Mock at lower level (the actual slow/external operation)
164+ OR use test doubles that preserve necessary behavior
165+ NOT the high-level method the test depends on
166+
167+ IF unsure what test depends on:
168+ Run test with real implementation FIRST
169+ Observe what actually needs to happen
170+ THEN add minimal mocking at the right level
171+
172+ Red flags:
173+ - "I'll mock this to be safe"
174+ - "This might be slow, better mock it"
175+ - Mocking without understanding the dependency chain
176+```
177+
178+## Anti-Pattern 4: Incomplete Mocks
179+
180+**The violation:**
181+```typescript
182+// ❌ BAD: Partial mock - only fields you think you need
183+const mockResponse = {
184+ status: 'success',
185+ data: { userId: '123', name: 'Alice' }
186+ // Missing: metadata that downstream code uses
187+};
188+
189+// Later: breaks when code accesses response.metadata.requestId
190+```
191+
192+**Why this is wrong:**
193+- **Partial mocks hide structural assumptions** - You only mocked fields you know about
194+- **Downstream code may depend on fields you didn't include** - Silent failures
195+- **Tests pass but integration fails** - Mock incomplete, real API complete
196+- **False confidence** - Test proves nothing about real behavior
197+
198+**The Iron Rule:** Mock the COMPLETE data structure as it exists in reality, not just fields your immediate test uses.
199+
200+**The fix:**
201+```typescript
202+// ✅ GOOD: Mirror real API completeness
203+const mockResponse = {
204+ status: 'success',
205+ data: { userId: '123', name: 'Alice' },
206+ metadata: { requestId: 'req-789', timestamp: 1234567890 }
207+ // All fields real API returns
208+};
209+```
210+
211+### Gate Function
212+
213+```
214+BEFORE creating mock responses:
215+ Check: "What fields does the real API response contain?"
216+
217+ Actions:
218+ 1. Examine actual API response from docs/examples
219+ 2. Include ALL fields system might consume downstream
220+ 3. Verify mock matches real response schema completely
221+
222+ Critical:
223+ If you're creating a mock, you must understand the ENTIRE structure
224+ Partial mocks fail silently when code depends on omitted fields
225+
226+ If uncertain: Include all documented fields
227+```
228+
229+## Anti-Pattern 5: Integration Tests as Afterthought
230+
231+**The violation:**
232+```
233+✅ Implementation complete
234+❌ No tests written
235+"Ready for testing"
236+```
237+
238+**Why this is wrong:**
239+- Testing is part of implementation, not optional follow-up
240+- TDD would have caught this
241+- Can't claim complete without tests
242+
243+**The fix:**
244+```
245+TDD cycle:
246+1. Write failing test
247+2. Implement to pass
248+3. Refactor
249+4. THEN claim complete
250+```
251+
252+## When Mocks Become Too Complex
253+
254+**Warning signs:**
255+- Mock setup longer than test logic
256+- Mocking everything to make test pass
257+- Mocks missing methods real components have
258+- Test breaks when mock changes
259+
260+**your human partner's question:** "Do we need to be using a mock here?"
261+
262+**Consider:** Integration tests with real components often simpler than complex mocks
263+
264+## TDD Prevents These Anti-Patterns
265+
266+**Why TDD helps:**
267+1. **Write test first** → Forces you to think about what you're actually testing
268+2. **Watch it fail** → Confirms test tests real behavior, not mocks
269+3. **Minimal implementation** → No test-only methods creep in
270+4. **Real dependencies** → You see what the test actually needs before mocking
271+
272+**If you're testing mock behavior, you violated TDD** - you added mocks without watching test fail against real code first.
273+
274+## Quick Reference
275+
276+| Anti-Pattern | Fix |
277+|--------------|-----|
278+| Assert on mock elements | Test real component or unmock it |
279+| Test-only methods in production | Move to test utilities |
280+| Mock without understanding | Understand dependencies first, mock minimally |
281+| Incomplete mocks | Mirror real API completely |
282+| Tests as afterthought | TDD - tests first |
283+| Over-complex mocks | Consider integration tests |
284+
285+## Red Flags
286+
287+- Assertion checks for `*-mock` test IDs
288+- Methods only called in test files
289+- Mock setup is >50% of test
290+- Test fails when you remove mock
291+- Can't explain why mock is needed
292+- Mocking "just to be safe"
293+
294+## The Bottom Line
295+
296+**Mocks are tools to isolate, not things to test.**
297+
298+If TDD reveals you're testing mock behavior, you've gone wrong.
299+
300+Fix: Test real behavior or question why you're mocking at all.
1@@ -0,0 +1,95 @@
2+---
3+name: using-superpowers
4+description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
5+---
6+
7+<EXTREMELY-IMPORTANT>
8+If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.
9+
10+IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
11+
12+This is not negotiable. This is not optional. You cannot rationalize your way out of this.
13+</EXTREMELY-IMPORTANT>
14+
15+## How to Access Skills
16+
17+**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.
18+
19+**In other environments:** Check your platform's documentation for how skills are loaded.
20+
21+# Using Skills
22+
23+## The Rule
24+
25+**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.
26+
27+```dot
28+digraph skill_flow {
29+ "User message received" [shape=doublecircle];
30+ "About to EnterPlanMode?" [shape=doublecircle];
31+ "Already brainstormed?" [shape=diamond];
32+ "Invoke brainstorming skill" [shape=box];
33+ "Might any skill apply?" [shape=diamond];
34+ "Invoke Skill tool" [shape=box];
35+ "Announce: 'Using [skill] to [purpose]'" [shape=box];
36+ "Has checklist?" [shape=diamond];
37+ "Create TodoWrite todo per item" [shape=box];
38+ "Follow skill exactly" [shape=box];
39+ "Respond (including clarifications)" [shape=doublecircle];
40+
41+ "About to EnterPlanMode?" -> "Already brainstormed?";
42+ "Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
43+ "Already brainstormed?" -> "Might any skill apply?" [label="yes"];
44+ "Invoke brainstorming skill" -> "Might any skill apply?";
45+
46+ "User message received" -> "Might any skill apply?";
47+ "Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
48+ "Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
49+ "Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
50+ "Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
51+ "Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
52+ "Has checklist?" -> "Follow skill exactly" [label="no"];
53+ "Create TodoWrite todo per item" -> "Follow skill exactly";
54+}
55+```
56+
57+## Red Flags
58+
59+These thoughts mean STOP—you're rationalizing:
60+
61+| Thought | Reality |
62+|---------|---------|
63+| "This is just a simple question" | Questions are tasks. Check for skills. |
64+| "I need more context first" | Skill check comes BEFORE clarifying questions. |
65+| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. |
66+| "I can check git/files quickly" | Files lack conversation context. Check for skills. |
67+| "Let me gather information first" | Skills tell you HOW to gather information. |
68+| "This doesn't need a formal skill" | If a skill exists, use it. |
69+| "I remember this skill" | Skills evolve. Read current version. |
70+| "This doesn't count as a task" | Action = task. Check for skills. |
71+| "The skill is overkill" | Simple things become complex. Use it. |
72+| "I'll just do this one thing first" | Check BEFORE doing anything. |
73+| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
74+| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |
75+
76+## Skill Priority
77+
78+When multiple skills could apply, use this order:
79+
80+1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
81+2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
82+
83+"Let's build X" → brainstorming first, then implementation skills.
84+"Fix this bug" → debugging first, then domain-specific skills.
85+
86+## Skill Types
87+
88+**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.
89+
90+**Flexible** (patterns): Adapt principles to context.
91+
92+The skill itself tells you which.
93+
94+## User Instructions
95+
96+Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.
1@@ -0,0 +1,139 @@
2+---
3+name: verification-before-completion
4+description: Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
5+---
6+
7+# Verification Before Completion
8+
9+## Overview
10+
11+Claiming work is complete without verification is dishonesty, not efficiency.
12+
13+**Core principle:** Evidence before claims, always.
14+
15+**Violating the letter of this rule is violating the spirit of this rule.**
16+
17+## The Iron Law
18+
19+```
20+NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE
21+```
22+
23+If you haven't run the verification command in this message, you cannot claim it passes.
24+
25+## The Gate Function
26+
27+```
28+BEFORE claiming any status or expressing satisfaction:
29+
30+1. IDENTIFY: What command proves this claim?
31+2. RUN: Execute the FULL command (fresh, complete)
32+3. READ: Full output, check exit code, count failures
33+4. VERIFY: Does output confirm the claim?
34+ - If NO: State actual status with evidence
35+ - If YES: State claim WITH evidence
36+5. ONLY THEN: Make the claim
37+
38+Skip any step = lying, not verifying
39+```
40+
41+## Common Failures
42+
43+| Claim | Requires | Not Sufficient |
44+|-------|----------|----------------|
45+| Tests pass | Test command output: 0 failures | Previous run, "should pass" |
46+| Linter clean | Linter output: 0 errors | Partial check, extrapolation |
47+| Build succeeds | Build command: exit 0 | Linter passing, logs look good |
48+| Bug fixed | Test original symptom: passes | Code changed, assumed fixed |
49+| Regression test works | Red-green cycle verified | Test passes once |
50+| Agent completed | VCS diff shows changes | Agent reports "success" |
51+| Requirements met | Line-by-line checklist | Tests passing |
52+
53+## Red Flags - STOP
54+
55+- Using "should", "probably", "seems to"
56+- Expressing satisfaction before verification ("Great!", "Perfect!", "Done!", etc.)
57+- About to commit/push/PR without verification
58+- Trusting agent success reports
59+- Relying on partial verification
60+- Thinking "just this once"
61+- Tired and wanting work over
62+- **ANY wording implying success without having run verification**
63+
64+## Rationalization Prevention
65+
66+| Excuse | Reality |
67+|--------|---------|
68+| "Should work now" | RUN the verification |
69+| "I'm confident" | Confidence ≠ evidence |
70+| "Just this once" | No exceptions |
71+| "Linter passed" | Linter ≠ compiler |
72+| "Agent said success" | Verify independently |
73+| "I'm tired" | Exhaustion ≠ excuse |
74+| "Partial check is enough" | Partial proves nothing |
75+| "Different words so rule doesn't apply" | Spirit over letter |
76+
77+## Key Patterns
78+
79+**Tests:**
80+```
81+✅ [Run test command] [See: 34/34 pass] "All tests pass"
82+❌ "Should pass now" / "Looks correct"
83+```
84+
85+**Regression tests (TDD Red-Green):**
86+```
87+✅ Write → Run (pass) → Revert fix → Run (MUST FAIL) → Restore → Run (pass)
88+❌ "I've written a regression test" (without red-green verification)
89+```
90+
91+**Build:**
92+```
93+✅ [Run build] [See: exit 0] "Build passes"
94+❌ "Linter passed" (linter doesn't check compilation)
95+```
96+
97+**Requirements:**
98+```
99+✅ Re-read plan → Create checklist → Verify each → Report gaps or completion
100+❌ "Tests pass, phase complete"
101+```
102+
103+**Agent delegation:**
104+```
105+✅ Agent reports success → Check VCS diff → Verify changes → Report actual state
106+❌ Trust agent report
107+```
108+
109+## Why This Matters
110+
111+From 24 failure memories:
112+- your human partner said "I don't believe you" - trust broken
113+- Undefined functions shipped - would crash
114+- Missing requirements shipped - incomplete features
115+- Time wasted on false completion → redirect → rework
116+- Violates: "Honesty is a core value. If you lie, you'll be replaced."
117+
118+## When To Apply
119+
120+**ALWAYS before:**
121+- ANY variation of success/completion claims
122+- ANY expression of satisfaction
123+- ANY positive statement about work state
124+- Committing, PR creation, task completion
125+- Moving to next task
126+- Delegating to agents
127+
128+**Rule applies to:**
129+- Exact phrases
130+- Paraphrases and synonyms
131+- Implications of success
132+- ANY communication suggesting completion/correctness
133+
134+## The Bottom Line
135+
136+**No shortcuts for verification.**
137+
138+Run the command. Read the output. THEN claim the result.
139+
140+This is non-negotiable.
1@@ -0,0 +1,29 @@
2+---
3+name: working-in-rescript
4+description: Use when writing or debugging code written in the Rescript language
5+---
6+
7+# Rescript Programming Language
8+
9+Rescript is a robustly typed language that compiles to efficient and human-readable JavaScript. It comes with a lightning fast compiler toolchain that scales to any codebase size.
10+
11+Refer to the documentation sets in this directory when working with Rescript. For difficult to debug cases, use the complete documentation, which includes examples.
12+
13+**IMPORTANT**: You must use the Rescript compiler to verify your changes. If the code does not compile, you are not done. Use skill **superpowers:systematic-troubleshooting** for issues with building the code.
14+
15+```bash
16+# Invoke the rescript compiler
17+pnpm exec rescript build
18+```
19+
20+## Documentation Sets
21+
22+- Complete documentation: **`llm-full.txt`**: The complete ReScript documentation including all examples and additional content
23+- Abridged documentation: **`llm-small.txt`**: A minimal version of the ReScript documentation, with the essential content for quick reference
24+
25+## Notes
26+
27+- The abridged documentation excludes the detailed examples, and supplementary information
28+- The complete documentation includes all content from the official documentation
29+- Package-specific documentation files contain only the content relevant to that package
30+- The content is automatically generated from the same source as the official documentation for the specific version
+16398,
-0
1@@ -0,0 +1,16398 @@
2+---
3+title: "API | ReScript"
4+metaTitle: "API"
5+description: "The ReScript API documentation"
6+canonical: "/docs/manual/api"
7+---
8+
9+# Introduction
10+
11+## Stdlib
12+
13+[Stdlib](/docs/manual/api/stdlib) is ReScript's new builtin standard library.
14+It will cover just about you need for day-to-day programming in ReScript and covers most of the built in JavaScript API.
15+
16+## Additional Libraries
17+
18+ReScript ships with these two additional modules in its standard library:
19+
20+- [Belt](/docs/manual/api/belt): immutable collections and extra helpers not available in JavaScript / [Stdlib](/docs/manual/api/stdlib).
21+- [Dom](/docs/manual/api/stdlibdom): Dom related types and modules. Contains our standardized types used by various userland DOM bindings.
22+
23+---
24+title: "Array & List"
25+description: "Arrays and List data structures"
26+canonical: "/docs/manual/array-and-list"
27+section: "Language Features"
28+order: 12
29+---
30+
31+# Array and List
32+
33+## Array
34+
35+Arrays are the main ordered data structure in ReScript. They can be randomly accessed, dynamically resized, and updated.
36+
37+<CodeTab labels={["ReScript", "JS Output"]}>
38+
39+```res
40+let myArray = ["hello", "world", "how are you"]
41+```
42+
43+```js
44+let myArray = ["hello", "world", "how are you"];
45+
46+export { myArray };
47+```
48+
49+</CodeTab>
50+
51+ReScript arrays' items must have the same type, i.e. homogeneous.
52+
53+### Usage
54+
55+#### Access
56+
57+Accessing items in an array will return an `option` and can be done like so:
58+
59+<CodeTab labels={["ReScript", "JS Output"]}>
60+
61+```res
62+let myArray = ["hello", "world", "how are you"]
63+
64+let firstItem = myArray[0] // Some("hello")
65+
66+let tenthItem = myArray->Array.get(10) // None
67+```
68+
69+```js
70+let myArray = ["hello", "world", "how are you"];
71+
72+let firstItem = myArray[0];
73+
74+let tenthItem = myArray[10];
75+
76+export { myArray, firstItem, tenthItem };
77+```
78+
79+</CodeTab>
80+
81+#### Update
82+
83+Items in an array can be updated by assigning a value to an index or using a function:
84+
85+<CodeTab labels={["ReScript", "JS Output"]}>
86+
87+```res
88+let myArray = ["hello", "world", "how are you"]
89+
90+myArray[0] = "hey" // now ["hey", "world", "how are you"]
91+
92+myArray->Array.push("?") // ["hey", "world", "how are you", "?"]
93+
94+myArray->Array.set(0, "bye") // ["bye", "world", "how are you", "?"]
95+```
96+
97+```js
98+let myArray = ["hello", "world", "how are you"];
99+
100+myArray[0] = "hey";
101+
102+myArray.push("?");
103+
104+myArray[0] = "bye";
105+
106+export { myArray };
107+```
108+
109+</CodeTab>
110+
111+### Array spreads
112+
113+**Since 11.1**
114+
115+You can spread arrays of the same type into new arrays:
116+
117+<CodeTab labels={["ReScript", "JS Output"]}>
118+
119+```res
120+let y = [1, 2]
121+let x = [4, 5, ...y]
122+let x2 = [4, 5, ...y, 7, ...y]
123+let x3 = [...y]
124+```
125+
126+```javascript
127+import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
128+
129+let y = [1, 2];
130+
131+let x = Belt_Array.concatMany([[4, 5], y]);
132+
133+let x2 = Belt_Array.concatMany([[4, 5], y, [7], y]);
134+
135+let x3 = Belt_Array.concatMany([y]);
136+
137+export { y, x, x2, x3 };
138+```
139+
140+</CodeTab>
141+
142+## List
143+
144+ReScript provides a singly linked list too. Lists are:
145+
146+- immutable
147+- fast at prepending items
148+- fast at getting the head
149+- slow at everything else
150+
151+<CodeTab labels={["ReScript", "JS Output"]}>
152+
153+```res
154+let myList = list{1, 2, 3}
155+```
156+
157+```js
158+let myList = {
159+ hd: 1,
160+ tl: {
161+ hd: 2,
162+ tl: {
163+ hd: 3,
164+ tl: /* [] */ 0,
165+ },
166+ },
167+};
168+
169+export { myList };
170+```
171+
172+</CodeTab>
173+
174+Like arrays, lists' items need to be of the same type.
175+
176+### Usage
177+
178+You'd use list for its resizability, its fast prepend (adding at the head), and its fast split, all of which are immutable and relatively efficient.
179+
180+Do **not** use list if you need to randomly access an item or insert at non-head position. Your code would end up obtuse and/or slow.
181+
182+For accessing deeper, see [destructuring](./pattern-matching-destructuring.mdx).
183+
184+#### Immutable Prepend
185+
186+Use the spread syntax:
187+
188+<CodeTab labels={["ReScript", "JS Output"]}>
189+
190+```res prelude
191+let myList = list{1, 2, 3}
192+let anotherList = list{0, ...myList}
193+```
194+
195+```js
196+var myList = {
197+ hd: 1,
198+ tl: {
199+ hd: 2,
200+ tl: {
201+ hd: 3,
202+ tl: 0,
203+ },
204+ },
205+};
206+
207+var anotherList = {
208+ hd: 0,
209+ tl: myList,
210+};
211+```
212+
213+</CodeTab>
214+
215+`myList` didn't mutate. `anotherList` is now `list{0, 1, 2, 3}`. This is efficient (constant time, not linear). `anotherList`'s last 3 elements are shared with `myList`!
216+
217+**Note that `list{a, ...b, ...c}` was a syntax error** before compiler v10.1. In general, the pattern should be used with care as its performance and allocation overhead are linear (`O(n)`).
218+
219+#### Access
220+
221+`switch` (described in the [pattern matching section](./pattern-matching-destructuring.mdx)) is usually used to access list items:
222+
223+<CodeTab labels={["ReScript", "JS Output"]}>
224+
225+```res
226+let message =
227+ switch myList {
228+ | list{} => "This list is empty"
229+ | list{first, second, ...rest} => "The list two items and a potenial remainder of items"
230+ | list{a, ...rest} => "The head of the list is the string " ++ Int.toString(a)
231+ }
232+```
233+
234+```js
235+let myList = {
236+ hd: 1,
237+ tl: {
238+ hd: 2,
239+ tl: {
240+ hd: 3,
241+ tl: /* [] */ 0,
242+ },
243+ },
244+};
245+
246+let anotherList = {
247+ hd: 0,
248+ tl: myList,
249+};
250+
251+let message =
252+ myList !== 0
253+ ? myList.tl !== 0
254+ ? "The list two items and a potenial remainder of items"
255+ : "The head of the list is the string " + (1).toString()
256+ : "This list is empty";
257+
258+export { myList, anotherList, message };
259+```
260+
261+</CodeTab>
262+
263+---
264+title: "Async / Await"
265+description: "Async / await for asynchronous operations"
266+canonical: "/docs/manual/async-await"
267+section: "Language Features"
268+order: 22
269+---
270+
271+{/* This prelude is used in many different followup examples, so we use it to shorten the noise of the example code. */}
272+
273+<div className="hidden">
274+
275+```res prelude
276+@val external fetchUserMail: string => promise<string> = "GlobalAPI.fetchUserMail"
277+@val external sendAnalytics: string => promise<unit> = "GlobalAPI.sendAnalytics"
278+```
279+
280+</div>
281+
282+{/* See https://github.com/cristianoc/rescript-compiler-experiments/pull/1#issuecomment-1131182023 for all async/await use-case examples */}
283+
284+# Async / Await
285+
286+ReScript comes with `async` / `await` support to make asynchronous, `Promise` based code easier to read and write. This feature is very similar to its JS equivalent, so if you are already familiar with JS' `async` / `await`, you will feel right at home.
287+
288+## How it looks
289+
290+Let's start with a quick example to show-case the syntax:
291+
292+<CodeTab labels={["ReScript", "JS Output"]}>
293+
294+```res
295+// Some fictive functionality that offers asynchronous network actions
296+@val external fetchUserMail: string => promise<string> = "GlobalAPI.fetchUserMail"
297+@val external sendAnalytics: string => promise<unit> = "GlobalAPI.sendAnalytics"
298+
299+// We use the `async` keyword to allow the use of `await` in the function body
300+let logUserDetails = async (userId: string) => {
301+ // We use `await` to fetch the user email from our fictive user endpoint
302+ let email = await fetchUserMail(userId)
303+
304+ await sendAnalytics(`User details have been logged for ${userId}`)
305+
306+ Console.log(`Email address for user ${userId}: ${email}`)
307+}
308+```
309+
310+```js
311+async function logUserDetails(userId) {
312+ let email = await GlobalAPI.fetchUserMail(userId);
313+ await GlobalAPI.sendAnalytics(`User details have been logged for ` + userId);
314+ console.log(`Email address for user ` + userId + `: ` + email);
315+}
316+
317+export { logUserDetails };
318+```
319+
320+</CodeTab>
321+
322+As we can see above, an `async` function is defined via the `async` keyword right before the function's parameter list. In the function body, we are now able to use the `await` keyword to explicitly wait for a `Promise` value and assign its content to a let binding `email`.
323+
324+You will probably notice that this looks very similar to `async` / `await` in JS, but there are still a few details that are specific to ReScript. The next few sections will go through all the details that are specific to the ReScript type system.
325+
326+## Basics
327+
328+- You may only use `await` in `async` function bodies
329+- `await` may only be called on a `promise` value
330+- `await` calls are expressions, therefore they can be used in pattern matching (`switch`)
331+- A function returning a `promise<'a>` is equivalent to an `async` function returning a value `'a` (important for writing signature files and bindings)
332+- `promise` values and types returned from an `async` function don't auto-collapse into a flat promise. See the details below.
333+
334+## Types and `async` functions
335+
336+### `async` function type signatures
337+
338+Function type signatures (i.e defined in signature files) don't require any special keywords for `async` usage. Whenever you want to type an `async` function, use a `promise` return type.
339+
340+```resi
341+// Demo.resi
342+
343+let fetchUserMail: string => promise<string>
344+```
345+
346+The same logic applies to type definitions in `.res` files:
347+
348+```res
349+// function type
350+type someAsyncFn = int => promise<int>
351+
352+// Function type annotation
353+let fetchData: string => promise<string> = async (userId) => {
354+ await fetchUserMail(userId)
355+}
356+```
357+
358+**BUT:** When typing `async` functions in your implementation files, you need to omit the `promise<'a>` type:
359+
360+```res
361+// This function is compiled into a `string => promise<string>` type.
362+// The promise<...> part is implicitly added by the compiler.
363+let fetchData = async (userId: string): string => {
364+ await fetchUserMail("test")
365+}
366+```
367+
368+For completeness reasons, let's expand the full signature and inline type definitions in one code snippet:
369+
370+```res nocheck
371+// Note how the inline return type uses `string`, while the type definition uses `promise<string>`
372+let fetchData: string => promise<string> = async (userId: string): string {
373+ await fetchUserMail(userId)
374+}
375+```
376+
377+**Note:** In a practical scenario you'd either use a type signature, or inline types, not both at the same time. In case you are interested in the design decisions, check out [this discussion](https://github.com/rescript-lang/rescript-compiler/pull/5913#issuecomment-1359003870).
378+
379+### Promises don't auto-collapse in async functions
380+
381+In JS, nested promises (i.e. `promise<promise<'a>>`) will automatically collapse into a flat promise (`promise<'a>`). This is not the case in ReScript. Use the `await` function to manually unwrap any nested promises within an `async` function instead.
382+
383+```res
384+let fetchData = async (userId: string): string => {
385+ // We can't just return the result of `fetchUserMail`, otherwise we'd get a
386+ // type error due to our function return type of type `string`
387+ await fetchUserMail(userId)
388+}
389+```
390+
391+## Error handling
392+
393+You may use `try / catch` or `switch` to handle exceptions during async execution.
394+
395+```res
396+// For simulation purposes
397+let authenticate = async () => {
398+ JsError.RangeError.throwWithMessage("Authentication failed.")
399+}
400+
401+let checkAuth = async () => {
402+ try {
403+ await authenticate()
404+ } catch {
405+ | JsExn(e) =>
406+ switch JsExn.message(e) {
407+ | Some(msg) => Console.log("JS error thrown: " ++ msg)
408+ | None => Console.log("Some other exception has been thrown")
409+ }
410+ }
411+}
412+```
413+
414+Note how we are essentially catching JS errors the same way as described in our [Exception](./exception.mdx#catch-rescript-exceptions-from-js) section.
415+
416+You may unify error and value handling in a single switch as well:
417+
418+```res
419+let authenticate = async () => {
420+ JsError.RangeError.throwWithMessage("Authentication failed.")
421+}
422+
423+let checkAuth = async () => {
424+ switch await authenticate() {
425+ | _ => Console.log("ok")
426+ | exception JsExn(e) =>
427+ switch JsExn.message(e) {
428+ | Some(msg) => Console.log("JS error thrown: " ++ msg)
429+ | None => Console.log("Some other exception has been thrown")
430+ }
431+ }
432+}
433+```
434+
435+**Important:** When using `await` with a `switch`, always make sure to put the actual await call in the `switch` expression, otherwise your `await` error will not be caught.
436+
437+## Piping `await` calls
438+
439+You may want to pipe the result of an `await` call right into another function.
440+This can be done by wrapping your `await` calls in a new `{}` closure.
441+
442+<CodeTab labels={["ReScript", "JS Output"]}>
443+
444+```res
445+@val external fetchUserMail: string => promise<string> = "GlobalAPI.fetchUserMail"
446+
447+let fetchData = async () => {
448+ let mail = {await fetchUserMail("1234")}->String.toUpperCase
449+ Console.log(`All upper-cased mail: ${mail}`)
450+}
451+```
452+
453+```js
454+async function fetchData() {
455+ let mail = (await GlobalAPI.fetchUserMail("1234")).toUpperCase();
456+ console.log(`All upper-cased mail: ` + mail);
457+}
458+
459+export { fetchData };
460+```
461+
462+</CodeTab>
463+
464+Note how the original closure was removed in the final JS output. No extra allocations!
465+
466+## Pattern matching on `await` calls
467+
468+`await` calls are just another kind of expression, so you can use `switch` pattern matching for more complex logic.
469+
470+<CodeTab labels={["ReScript", "JS Output"]}>
471+
472+```res
473+@val external fetchUserMail: string => promise<string> = "GlobalAPI.fetchUserMail"
474+
475+let fetchData = async () => {
476+ switch (await fetchUserMail("user1"), await fetchUserMail("user2")) {
477+ | (user1Mail, user2Mail) => {
478+ Console.log("user 1 mail: " ++ user1Mail)
479+ Console.log("user 2 mail: " ++ user2Mail)
480+ }
481+
482+ | exception JsExn(err) => Console.log2("Some error occurred", err)
483+ }
484+}
485+```
486+
487+```js
488+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
489+
490+async function fetchData() {
491+ let val;
492+ let val$1;
493+ try {
494+ val = await GlobalAPI.fetchUserMail("user1");
495+ val$1 = await GlobalAPI.fetchUserMail("user2");
496+ } catch (raw_err) {
497+ let err = Primitive_exceptions.internalToException(raw_err);
498+ if (err.RE_EXN_ID === "JsExn") {
499+ console.log("Some error occurred", err._1);
500+ return;
501+ }
502+ throw err;
503+ }
504+ console.log("user 1 mail: " + val);
505+ console.log("user 2 mail: " + val$1);
506+}
507+
508+export { fetchData };
509+```
510+
511+</CodeTab>
512+
513+## `await` multiple promises
514+
515+We can utilize the `Promise` module to handle multiple promises. E.g. let's use `Promise.all` to wait for multiple promises before continuing the program:
516+
517+```res
518+let pauseReturn = (value, timeout) => {
519+ Promise.make((resolve, _reject) => {
520+ setTimeout(() => {
521+ resolve(value)
522+ }, timeout)->ignore
523+ })
524+}
525+
526+let logMultipleValues = async () => {
527+ let promise1 = pauseReturn("value1", 2000)
528+ let promise2 = pauseReturn("value2", 1200)
529+ let promise3 = pauseReturn("value3", 500)
530+
531+ let all = await Promise.all([promise1, promise2, promise3])
532+
533+ switch all {
534+ | [v1, v2, v3] => Console.log(`All values: ${v1}, ${v2}, ${v3}`)
535+ | _ => Console.log("this should never happen")
536+ }
537+}
538+```
539+
540+## JS Interop with `async` functions
541+
542+`async` / `await` practically works with any function that returns a `promise<'a>` value. Map your `promise` returning function via an `external`, and use it in an `async` function as usual.
543+
544+Here's a full example of using the MDN `fetch` API, using `async` / `await` to simulate a login:
545+
546+```res nocheck
547+// A generic Response type for typing our fetch requests
548+module Response = {
549+ type t<'data>
550+ @send external json: t<'data> => promise<'data> = "json"
551+}
552+
553+// A binding to our globally available `fetch` function. `fetch` is a
554+// standardized function to retrieve data from the network that is available in
555+// all modern browsers.
556+@val @scope("globalThis")
557+external fetch: (
558+ string,
559+ 'params,
560+) => promise<Response.t<{"token": Nullable.t<string>, "error": Nullable.t<string>}>> =
561+ "fetch"
562+
563+// We now use our asynchronous `fetch` function to simulate a login.
564+// Note how we use `await` with regular functions returning a `promise`.
565+let login = async (email: string, password: string) => {
566+ let body = {
567+ "email": email,
568+ "password": password,
569+ }
570+
571+ let params = {
572+ "method": "POST",
573+ "headers": {
574+ "Content-Type": "application/json",
575+ },
576+ "body": Json.stringifyAny(body),
577+ }
578+
579+ try {
580+ let response = await fetch("https://reqres.in/api/login", params)
581+ let data = await response->Response.json
582+
583+ switch Nullable.toOption(data["error"]) {
584+ | Some(msg) => Error(msg)
585+ | None =>
586+ switch Nullable.toOption(data["token"]) {
587+ | Some(token) => Ok(token)
588+ | None => Error("Didn't return a token")
589+ }
590+ }
591+ } catch {
592+ | _ => Error("Unexpected network error occurred")
593+ }
594+}
595+```
596+
597+---
598+title: "Attribute (Decorator)"
599+description: "Annotations in ReScript"
600+canonical: "/docs/manual/attribute"
601+section: "Language Features"
602+order: 26
603+---
604+
605+# Attribute (Decorator)
606+
607+Like many other languages, ReScript allows annotating a piece of code to express extra functionality. Here's an example:
608+
609+<CodeTab labels={["ReScript", "JS Output"]}>
610+
611+```res
612+@inline
613+let mode = "dev"
614+
615+let mode2 = mode
616+```
617+
618+```js
619+let mode2 = "dev";
620+
621+export { mode2 };
622+```
623+
624+</CodeTab>
625+
626+The `@inline` annotation tells `mode`'s value to be inlined into its usage sites (see output). We call such annotation "attribute" (or "decorator" in JavaScript).
627+
628+An attribute starts with `@` and goes before the item it annotates. In the above example, it's hooked onto the let binding.
629+
630+## Usage
631+
632+> **Note:** In previous versions (< 8.3) all our interop related attributes started with a `bs.` prefix (`bs.module`, `bs.val`). Our formatter will automatically drop them in newer ReScript versions.
633+
634+You can put an attribute almost anywhere. You can even add extra data to them by using them visually like a function call. Here are a few famous attributes (explained in other sections):
635+
636+<CodeTab labels={["ReScript", "JS Output"]}>
637+
638+```res
639+@@warning("-27")
640+
641+
642+@unboxed
643+type a = Name(string)
644+
645+@val external message: string = "message"
646+
647+type student = {
648+ age: int,
649+ @as("aria-label") ariaLabel: string,
650+}
651+
652+@deprecated
653+let customDouble = foo => foo * 2
654+
655+@deprecated("Use SomeOther.customTriple instead")
656+let customTriple = foo => foo * 3
657+```
658+
659+```js
660+function customDouble(foo) {
661+ return foo << 1;
662+}
663+
664+function customTriple(foo) {
665+ return (foo * 3) | 0;
666+}
667+
668+export { customDouble, customTriple };
669+```
670+
671+</CodeTab>
672+
673+1. `@@warning("-27")` is a standalone attribute that annotates the entire file. Those attributes start with `@@`. Here, it carries the data `"-27"`. You can find a full list of all available warnings [here](./warning-numbers.mdx).
674+2. `@unboxed` annotates the type definition.
675+3. `@val` annotates the `external` statement.
676+4. `@as("aria-label")` annotates the `ariaLabel` record field.
677+5. `@deprecated` annotates the `customDouble` expression. This shows a warning while compiling telling consumers to not rely on this method long-term.
678+6. `@deprecated("Use SomeOther.customTriple instead")` annotates the `customTriple` expression with a string to describe the reason for deprecation.
679+
680+For a list of all decorators and their usage, please refer to the [Syntax Lookup](../../syntax-lookup/) page.
681+
682+## Extension Point
683+
684+There's a second category of attributes, called "extension points" (a remnant term of our early systems):
685+
686+<CodeTab labels={["ReScript", "JS Output"]}>
687+
688+```res
689+%raw("var a = 1")
690+```
691+
692+```js
693+((var a = 1));
694+```
695+
696+</CodeTab>
697+
698+Extension points are attributes that don't _annotate_ an item; they _are_ the item. Usually they serve as placeholders for the compiler to implicitly substitute them with another item.
699+
700+Extension points start with `%`. A standalone extension point (akin to a standalone regular attribute) starts with `%%`.
701+
702+For a list of all extension points and their usage, please refer to the [Syntax Lookup](../../syntax-lookup/) page.
703+
704+---
705+title: "Bind to Global JS Values"
706+description: "JS interop with global JS values in ReScript"
707+canonical: "/docs/manual/bind-to-global-js-values"
708+section: "JavaScript Interop"
709+order: 8
710+---
711+
712+# Bind to Global JS Values
713+
714+**First**, make sure the value you'd like to model doesn't already exist in our [provided API](/docs/manual/api/stdlib).
715+
716+Some JS values, like `setTimeout`, live in the global scope. You can bind to them like so:
717+
718+<CodeTab labels={["ReScript", "JS Output"]}>
719+
720+```res
721+@val external setTimeout: (unit => unit, int) => float = "setTimeout"
722+@val external clearTimeout: float => unit = "clearTimeout"
723+```
724+
725+```js
726+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
727+```
728+
729+</CodeTab>
730+
731+(We already provide `setTimeout`, `clearTimeout` and others in the [Core API](/docs/manual/api/stdlib) module).
732+
733+This binds to the JavaScript [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrworkerGlobalScope/setTimeout) methods and the corresponding `clearTimeout`. The `external`'s type annotation specifies that `setTimeout`:
734+
735+- Takes a function that accepts `unit` and returns `unit` (which on the JS side turns into a function that accepts nothing and returns nothing aka `undefined`),
736+- and an integer that specifies the duration before calling said function,
737+- returns a number that is the timeout's ID. This number might be big, so we're modeling it as a float rather than the 32-bit int.
738+
739+### Tips & Tricks
740+
741+**The above isn't ideal**. See how `setTimeout` returns a `float` and `clearTimeout` accepts one. There's no guarantee that you're passing the float created by `setTimeout` into `clearTimeout`! For all we know, someone might pass it `Math.random()` into the latter.
742+
743+We're in a language with a great type system now! Let's leverage a popular feature to solve this problem: abstract types.
744+
745+<CodeTab labels={["ReScript", "JS Output"]}>
746+
747+```res
748+type timerId
749+@val external setTimeout: (unit => unit, int) => timerId = "setTimeout"
750+@val external clearTimeout: timerId => unit = "clearTimeout"
751+
752+let id = setTimeout(() => Console.log("hello"), 100)
753+clearTimeout(id)
754+```
755+
756+```js
757+let id = setTimeout(() => {
758+ console.log("hello");
759+}, 100);
760+
761+clearTimeout(id);
762+
763+export { id };
764+```
765+
766+</CodeTab>
767+
768+Clearly, `timerId` is a type that can only be created by `setTimeout`! Now we've guaranteed that `clearTimeout` _will_ be passed a valid ID. Whether it's a number under the hood is now a mere implementation detail.
769+
770+Since `external`s are inlined, we end up with JS output as readable as hand-written JS.
771+
772+## Global Modules
773+
774+If you want to bind to a value inside a global module, e.g. `Math.random`, attach a `scope` to your `val` external:
775+
776+<CodeTab labels={["ReScript", "JS Output"]}>
777+
778+```res
779+@scope("Math") @val external random: unit => float = "random"
780+let someNumber = random()
781+```
782+
783+```js
784+let someNumber = Math.random();
785+
786+export { someNumber };
787+```
788+
789+</CodeTab>
790+
791+you can bind to an arbitrarily deep object by passing a tuple to `scope`:
792+
793+<CodeTab labels={["ReScript", "JS Output"]}>
794+
795+```res
796+@val @scope(("window", "location", "ancestorOrigins"))
797+external length: int = "length"
798+```
799+
800+```js
801+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
802+```
803+
804+</CodeTab>
805+
806+This binds to `window.location.ancestorOrigins.length`.
807+
808+## Special Global Values
809+
810+Global values like `__filename` and `__DEV__` don't always exist; you can't even model them as an `option`, since the mere act of referring to them in ReScript (then compiled into JS) would trigger the usual `Uncaught ReferenceError: __filename is not defined` error in e.g. the browser environment.
811+
812+For these troublesome global values, ReScript provides a special approach: `%external(a_single_identifier)`.
813+
814+<CodeTab labels={["ReScript", "JS Output"]}>
815+
816+```res
817+switch %external(__DEV__) {
818+| Some(_) => Console.log("dev mode")
819+| None => Console.log("production mode")
820+}
821+```
822+
823+```js
824+import * as Js from "@rescript/runtime/lib/es6/Js.js";
825+
826+let match = Js.undefinedToOption(
827+ typeof __DEV__ === "undefined" ? undefined : __DEV__,
828+);
829+
830+if (match !== undefined) {
831+ console.log("dev mode");
832+} else {
833+ console.log("production mode");
834+}
835+```
836+
837+</CodeTab>
838+
839+That first line's `typeof` check won't trigger a JS ReferenceError.
840+
841+Another example:
842+
843+<CodeTab labels={["ReScript", "JS Output"]}>
844+
845+```res
846+switch %external(__filename) {
847+| Some(f) => Console.log(f)
848+| None => Console.log("non-node environment")
849+};
850+```
851+
852+```js
853+import * as Js from "@rescript/runtime/lib/es6/Js.js";
854+import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
855+
856+let f = Js.undefinedToOption(
857+ typeof __filename === "undefined" ? undefined : __filename,
858+);
859+
860+if (f !== undefined) {
861+ console.log(Primitive_option.valFromOption(f));
862+} else {
863+ console.log("non-node environment");
864+}
865+```
866+
867+</CodeTab>
868+
869+{/* TODO: revamp this page. Not good. Tell to use globalThis["foo"], and look in our stdlib */}
870+
871+---
872+title: "Bind to JS Function"
873+description: "JS interop with functions in ReScript"
874+canonical: "/docs/manual/bind-to-js-function"
875+section: "JavaScript Interop"
876+order: 6
877+---
878+
879+# Function
880+
881+Binding a JS function is like binding any other value:
882+
883+<CodeTab labels={["ReScript", "JS Output"]}>
884+
885+```res
886+// Import nodejs' path.dirname
887+@module("path") external dirname: string => string = "dirname"
888+let root = dirname("/User/github") // returns "User"
889+```
890+
891+```js
892+import * as Path from "path";
893+
894+let root = Path.dirname("/User/github");
895+
896+export { root };
897+```
898+
899+</CodeTab>
900+
901+We also expose a few special features, described below.
902+
903+## Labeled Arguments
904+
905+ReScript has [function](./function.mdx) signature. These work on an `external` too! You'd use them to _fix_ a JS function's unclear usage. Assuming we're modeling this:
906+
907+```js
908+// MyGame.js
909+
910+function draw(x, y, border) {
911+ // suppose `border` is optional and defaults to false
912+}
913+draw(10, 20);
914+draw(20, 20, true);
915+```
916+
917+It'd be nice if on ReScript's side, we can bind & call `draw` while labeling things a bit:
918+
919+<CodeTab labels={["ReScript", "JS Output"]}>
920+
921+```res
922+@module("MyGame")
923+external draw: (~x: int, ~y: int, ~border: bool=?) => unit = "draw"
924+
925+draw(~x=10, ~y=20, ~border=true)
926+draw(~x=10, ~y=20)
927+```
928+
929+```js
930+import * as MyGame from "MyGame";
931+
932+MyGame.draw(10, 20, true);
933+
934+MyGame.draw(10, 20);
935+```
936+
937+</CodeTab>
938+
939+We've compiled to the same function, but now the usage is much clearer on the ReScript side thanks to labels!
940+
941+Note that you can freely reorder the labels on the ReScript side; they'll always correctly appear in their declaration order in the JavaScript output:
942+
943+<CodeTab labels={["ReScript", "JS Output"]}>
944+
945+```res
946+@module("MyGame")
947+external draw: (~x: int, ~y: int, ~border: bool=?) => unit = "draw"
948+
949+draw(~x=10, ~y=20)
950+draw(~y=20, ~x=10)
951+```
952+
953+```js
954+import * as MyGame from "MyGame";
955+
956+MyGame.draw(10, 20);
957+
958+MyGame.draw(10, 20);
959+```
960+
961+</CodeTab>
962+
963+## Object Method
964+
965+Functions attached to JS objects (other than JS modules) require a special way of binding to them, using `send`:
966+
967+<CodeTab labels={["ReScript", "JS Output"]}>
968+
969+```res
970+type document // abstract type for a document object
971+@send external getElementById: (document, string) => Dom.element = "getElementById"
972+@val external doc: document = "document"
973+
974+let el = getElementById(doc, "myId")
975+```
976+
977+```js
978+let el = document.getElementById("myId");
979+
980+export { el };
981+```
982+
983+</CodeTab>
984+
985+In a `send`, the object is always the first argument. Actual arguments of the method follow (this is a bit what modern OOP objects are really).
986+
987+### Chaining
988+
989+Ever used `foo().bar().baz()` chaining ("fluent api") in JS OOP? We can model that in ReScript too, through the [pipe operator](./pipe.mdx).
990+
991+### Nested function call
992+
993+`@send` can also accept a `@scope(("itemOne","itemTwo"))` to access a function on a nested property.
994+
995+<CodeTab labels={["ReScript", "JS Output"]}>
996+```res
997+type stripe
998+
999+@module("stripe") @new
1000+external make: string => stripe = "default"
1001+
1002+type createSession = {}
1003+
1004+type sessionResult
1005+
1006+@send
1007+@scope(("checkout", "sessions"))
1008+external createCheckoutSession: (stripe, createSession) =>
1009+Promise.t<sessionResult> = "create"
1010+
1011+let stripe = make("sk\_...")
1012+let session = stripe->createCheckoutSession({})
1013+
1014+````
1015+```js
1016+import Stripe from "stripe";
1017+
1018+let stripe = new Stripe("sk\_...");
1019+
1020+let session = stripe.checkout.sessions.create({});
1021+
1022+export {
1023+ stripe,
1024+ session,
1025+}
1026+````
1027+
1028+</CodeTab>
1029+
1030+## Variadic Function Arguments
1031+
1032+You might have JS functions that take an arbitrary amount of arguments. ReScript supports modeling those, under the condition that the arbitrary arguments part is homogenous (aka of the same type). If so, add `variadic` to your `external`.
1033+
1034+<CodeTab labels={["ReScript", "JS Output"]}>
1035+
1036+```res
1037+@module("path") @variadic
1038+external join: array<string> => string = "join"
1039+
1040+let v = join(["a", "b"])
1041+```
1042+
1043+```js
1044+import * as Path from "path";
1045+
1046+let v = Path.join("a", "b");
1047+
1048+export { v };
1049+```
1050+
1051+</CodeTab>
1052+
1053+`module` will be explained in [Import from/Export to JS](./import-from-export-to-js.mdx).
1054+
1055+## Modeling Polymorphic Function
1056+
1057+Apart from the above special-case, JS functions in general are often arbitrarily overloaded in terms of argument types and number. How would you bind to those?
1058+
1059+### Trick 1: Multiple `external`s
1060+
1061+If you can exhaustively enumerate the many forms an overloaded JS function can take, simply bind to each differently:
1062+
1063+<CodeTab labels={["ReScript", "JS Output"]}>
1064+
1065+```res
1066+@module("MyGame") external drawCat: unit => unit = "draw"
1067+@module("MyGame") external drawDog: (~giveName: string) => unit = "draw"
1068+@module("MyGame") external draw: (string, ~useRandomAnimal: bool) => unit = "draw"
1069+```
1070+
1071+```js
1072+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
1073+```
1074+
1075+</CodeTab>
1076+
1077+Note how all three externals bind to the same JS function, `draw`.
1078+
1079+### Trick 2: Polymorphic Variant + `unwrap`
1080+
1081+If you have the irresistible urge of saying "if only this JS function argument was a variant instead of informally being either `string` or `int`", then good news: we do provide such `external` features through annotating a parameter as a polymorphic variant! Assuming you have the following JS function you'd like to bind to:
1082+
1083+```js
1084+function padLeft(value, padding) {
1085+ if (typeof padding === "number") {
1086+ return Array(padding + 1).join(" ") + value;
1087+ }
1088+ if (typeof padding === "string") {
1089+ return padding + value;
1090+ }
1091+ throw new Error(`Expected string or number, got '${padding}'.`);
1092+}
1093+```
1094+
1095+Here, `padding` is really conceptually a variant. Let's model it as such.
1096+
1097+<CodeTab labels={["ReScript", "JS Output"]}>
1098+
1099+```res
1100+@val
1101+external padLeft: (
1102+ string,
1103+ @unwrap [
1104+ | #Str(string)
1105+ | #Int(int)
1106+ ])
1107+ => string = "padLeft"
1108+padLeft("Hello World", #Int(4))
1109+padLeft("Hello World", #Str("Message from ReScript: "))
1110+```
1111+
1112+```js
1113+padLeft("Hello World", 4);
1114+
1115+padLeft("Hello World", "Message from ReScript: ");
1116+```
1117+
1118+</CodeTab>
1119+
1120+Obviously, the JS side couldn't have an argument that's a polymorphic variant! But here, we're just piggy backing on poly variants' type checking and syntax. The secret is the `@unwrap` annotation on the type. It strips the variant constructors and compile to just the payload's value. See the output.
1121+
1122+## Constrain Arguments Better
1123+
1124+Consider the Node `fs.readFileSync`'s second argument. It can take a string, but really only a defined set: `"ascii"`, `"utf8"`, etc. You can still bind it as a string, but we can use poly variants + `string` to ensure that our usage's more correct:
1125+
1126+<CodeTab labels={["ReScript", "JS Output"]}>
1127+
1128+```res
1129+@module("fs")
1130+external readFileSync: (
1131+ ~name: string,
1132+ @string [
1133+ | #utf8
1134+ | @as("ascii") #useAscii
1135+ ],
1136+) => string = "readFileSync"
1137+
1138+readFileSync(~name="xx.txt", #useAscii)
1139+```
1140+
1141+```js
1142+import * as Fs from "fs";
1143+
1144+Fs.readFileSync("xx.txt", "ascii");
1145+```
1146+
1147+</CodeTab>
1148+
1149+- Attaching `@string` to the whole poly variant type makes its constructor compile to a string of the same name.
1150+- Attaching a `@as("bla")` to a constructor lets you customize the final string.
1151+
1152+And now, passing something like `"myOwnUnicode"` or other variant constructor names to `readFileSync` would correctly error.
1153+
1154+Aside from string, you can also compile an argument to an int, using `int` instead of `string` in a similar way:
1155+
1156+<CodeTab labels={["ReScript", "JS Output"]}>
1157+
1158+```res
1159+@val
1160+external testIntType: (
1161+ @int [
1162+ | #onClosed
1163+ | @as(20) #onOpen
1164+ | #inBinary
1165+ ])
1166+ => int = "testIntType"
1167+testIntType(#inBinary)
1168+```
1169+
1170+```js
1171+testIntType(21);
1172+```
1173+
1174+</CodeTab>
1175+
1176+`onClosed` compiles to `0`, `onOpen` to `20` and `inBinary` to **`21`**.
1177+
1178+## Unknown for type safety
1179+
1180+It is best practice to inspect data received from untrusted external functions to ensure it contains what you expect. This helps avoid run-time crashes and unexpected behavior. If you're certain about what an external function returns, simply assert the return value as `string` or `array<int>` or whatever you want it to be. Otherwise use `unknown`. The ReScript type system will prevent you from using an `unknown` until you first inspect it and "convert" it using JSON parsing utilities or similar tools.
1181+
1182+Consider the example below of two external functions that access the value of a property on a JavaScript object. `getPropertyUnsafe` returns an `'a`, which means "anything you want it to be." ReScript allows you to use this value as a `string` or `array` or any other type. Quite convenient! But if the property is missing or contains something unexpected, your code might break. You can make the binding more safe by changing `'a` to `string` or `option<'a>`, but this doesn't completely eliminate the problem.
1183+
1184+The `getPropertySafe` function returns an `unknown`, which could be `null` or a `string` or anything else. But ReScript prevents you from using this value inappropriately until it has been safely parsed.
1185+
1186+```res
1187+@get_index external getPropertyUnsafe: ({..}, string) => 'a = ""
1188+@get_index external getPropertySafe: ({..}, string) => unknown = ""
1189+
1190+let person = {"name": "Bob", "age": 12}
1191+
1192+let greeting1 = "Hello, " ++ getPropertyUnsafe(person, "name") // works (this time!)
1193+// let greeting2 = "Hello, " ++ getPropertySafe(person, "name") // syntax error
1194+```
1195+
1196+## Special-case: Event Listeners
1197+
1198+One last trick with polymorphic variants:
1199+
1200+<CodeTab labels={["ReScript", "JS Output"]}>
1201+
1202+```res
1203+type readline
1204+
1205+@send
1206+external on: (
1207+ readline,
1208+ @string [
1209+ | #close(unit => unit)
1210+ | #line(string => unit)
1211+ ]
1212+ )
1213+ => readline = "on"
1214+
1215+let register = rl =>
1216+ rl
1217+ ->on(#close(event => ()))
1218+ ->on(#line(line => Console.log(line)));
1219+```
1220+
1221+```js
1222+function register(rl) {
1223+ return rl
1224+ .on("close", (event) => {})
1225+ .on("line", (line) => {
1226+ console.log(line);
1227+ });
1228+}
1229+
1230+export { register };
1231+```
1232+
1233+</CodeTab>
1234+
1235+{/* TODO: GADT phantom type */}
1236+
1237+## Fixed Arguments
1238+
1239+Sometimes it's convenient to bind to a function using an `external`, while passing predetermined argument values to the JS function:
1240+
1241+<CodeTab labels={["ReScript", "JS Output"]}>
1242+
1243+```res
1244+@val
1245+external processOnExit: (
1246+ @as("exit") _,
1247+ int => unit
1248+) => unit = "process.on"
1249+
1250+processOnExit(exitCode =>
1251+ Console.log("error code: " ++ Int.toString(exitCode))
1252+);
1253+```
1254+
1255+```js
1256+process.on("exit", (exitCode) => {
1257+ console.log("error code: " + exitCode.toString());
1258+});
1259+```
1260+
1261+</CodeTab>
1262+
1263+The `@as("exit")` and the placeholder `_` argument together indicates that you want the first argument to compile to the string `"exit"`. You can also use any JSON literal with `as`: ``@as(json`true`)``, ``@as(json`{"name": "John"}`)``, etc.
1264+
1265+## Ignore arguments
1266+
1267+You can also explicitly "hide" `external` function parameters in the JS output, which may be useful if you want to add type constraints to other parameters without impacting the JS side:
1268+
1269+<CodeTab labels={["ReScript", "JS Output"]}>
1270+
1271+```res
1272+@val external doSomething: (@ignore 'a, 'a) => unit = "doSomething"
1273+
1274+doSomething("this only shows up in ReScript code", "test")
1275+```
1276+
1277+```js
1278+doSomething("test");
1279+```
1280+
1281+</CodeTab>
1282+
1283+**Note:** It's a pretty niche feature, mostly used to map to polymorphic JS APIs.
1284+
1285+## Modeling `this`-based Callbacks
1286+
1287+Many JS libraries have callbacks which rely on this (the source), for example:
1288+
1289+```js
1290+x.onload = function (v) {
1291+ console.log(this.response + v);
1292+};
1293+```
1294+
1295+Here, `this` would point to `x` (actually, it depends on how `onload` is called, but we digress). It's not correct to declare `x.onload` of type `(. unit) -> unit`. Instead, we introduced a special attribute, `this`, which allows us to type `x` as so:
1296+
1297+<CodeTab labels={["ReScript", "JS Output"]}>
1298+
1299+```res
1300+type x
1301+@val external x: x = "x"
1302+@set external setOnload: (x, @this ((x, int) => unit)) => unit = "onload"
1303+@get external resp: x => int = "response"
1304+setOnload(x, @this (o, v) => Console.log(resp(o) + v))
1305+```
1306+
1307+```js
1308+x.onload = function (v) {
1309+ let o = this;
1310+ console.log((o.response + v) | 0);
1311+};
1312+```
1313+
1314+</CodeTab>
1315+
1316+`@this` reserves the first parameter for the `this` value, and for arity of 0, there is no need for a redundant `unit` type.
1317+
1318+## Function Nullable Return Value Wrapping
1319+
1320+For JS functions that return a value that can also be `undefined` or `null`, we provide `@return(...)`. To automatically convert that value to an `option` type (recall that ReScript `option` type's `None` value only compiles to `undefined` and not `null`).
1321+
1322+<CodeTab labels={["ReScript", "JS Output"]}>
1323+
1324+```res
1325+type element
1326+type dom
1327+
1328+@send @return(nullable)
1329+external getElementById: (dom, string) => option<element> = "getElementById"
1330+
1331+let test = dom => {
1332+ let elem = dom->(getElementById("haha"))
1333+ switch (elem) {
1334+ | None => 1
1335+ | Some(_ui) => 2
1336+ }
1337+}
1338+```
1339+
1340+```js
1341+function test(dom) {
1342+ let elem = dom.getElementById("haha");
1343+ if (elem == null) {
1344+ return 1;
1345+ } else {
1346+ return 2;
1347+ }
1348+}
1349+
1350+export { test };
1351+```
1352+
1353+</CodeTab>
1354+
1355+`return(nullable)` attribute will automatically convert `null` and `undefined` to `option` type.
1356+
1357+Currently 4 directives are supported: `null_to_opt`, `undefined_to_opt`, `nullable` and `identity`.
1358+
1359+{/* When the return type is unit: the compiler will append its return value with an OCaml unit literal to make sure it does return unit. Its main purpose is to make the user consume FFI in idiomatic OCaml code, the cost is very very small and the compiler will do smart optimizations to remove it when the returned value is not used (mostly likely). */}
1360+
1361+`identity` will make sure that compiler will do nothing about the returned value. It is rarely used, but introduced here for debugging purpose.
1362+
1363+## Tagged template functions
1364+
1365+**Since 11.1**
1366+
1367+**Experimental** You can easily bind to [JS tagged template functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates).
1368+Tag functions in JS expect as input an array of strings and variadic parameters for the arguments of the interpolation.
1369+To bind to those functions in ReScript, the binding signature must have two arrays as arguments,
1370+the first one being an array of strings and the second can be an array of anything.
1371+You add the `@taggedTemplate` annotation and you're good to go!
1372+
1373+<CodeTab labels={["ReScript", "JS Output"]}>
1374+
1375+```res
1376+// see https://bun.sh/docs/runtime/shell
1377+type result = {exitCode: int}
1378+@module("bun") @taggedTemplate
1379+external sh: (array<string>, array<string>) => promise<result> = "$"
1380+
1381+let filename = "index.res"
1382+let result = await sh`ls ${filename}`
1383+```
1384+
1385+```js
1386+import * as $$Bun from "bun";
1387+
1388+let filename = "index.res";
1389+
1390+let result = await $$Bun.$`ls ${filename}`;
1391+
1392+export { filename, result };
1393+```
1394+
1395+</CodeTab>
1396+
1397+Notice that it gets compiled to tagged template literals in JS, which allows
1398+to use JS tools that only work on the literals and not by calling directly the tag function.
1399+
1400+There are plenty of useful JS tools you can bind to, like [`gql`](https://github.com/apollographql/graphql-tag),
1401+[`sql`](https://github.com/porsager/postgres), [`css`](https://github.com/mayank99/ecsstatic) and a lot others!
1402+
1403+---
1404+title: "Bind to JS Object"
1405+description: "Interop with JS objects in ReScript"
1406+canonical: "/docs/manual/bind-to-js-object"
1407+section: "JavaScript Interop"
1408+order: 5
1409+---
1410+
1411+# Bind to JS Object
1412+
1413+JavaScript objects are a combination of several use-cases:
1414+
1415+- As a "record" or "struct" in other languages (like ReScript and C).
1416+- As a hash map.
1417+- As a class.
1418+- As a module to import/export.
1419+
1420+ReScript cleanly separates the binding methods for JS object based on these 4 use-cases. This page documents the first three. Binding to JS module objects is described in the [Import from/Export to JS](./import-from-export-to-js.mdx) section.
1421+
1422+{/* TODO: mention scope here too? */}
1423+
1424+## Bind to Record-like JS Objects
1425+
1426+### Bind Using ReScript Record
1427+
1428+If your JavaScript object has fixed fields, then it's conceptually like a ReScript record. Since a ReScript record compiles to a clean JavaScript object, you can definitely type a JS object as a ReScript record!
1429+
1430+<CodeTab labels={["ReScript", "JS Output"]}>
1431+
1432+```res
1433+type person = {
1434+ name: string,
1435+ friends: array<string>,
1436+ age: int,
1437+}
1438+
1439+@module("MySchool") external john: person = "john"
1440+
1441+let johnName = john.name
1442+```
1443+
1444+```js
1445+import * as MySchool from "MySchool";
1446+
1447+let johnName = MySchool.john.name;
1448+
1449+export { johnName };
1450+```
1451+
1452+</CodeTab>
1453+
1454+External is documented [here](./external.mdx). `@module` is documented [here](./import-from-export-to-js.mdx).
1455+
1456+If you want or need to use different field names on the ReScript and the JavaScript side, you can use the `@as` decorator:
1457+
1458+<CodeTab labels={["ReScript", "JS Output"]}>
1459+
1460+```res
1461+type action = {
1462+ @as("type") type_: string
1463+}
1464+
1465+let action = {type_: "ADD_USER"}
1466+```
1467+
1468+```js
1469+let action = {
1470+ type: "ADD_USER",
1471+};
1472+
1473+export { action };
1474+```
1475+
1476+</CodeTab>
1477+
1478+This is useful to map to JavaScript attribute names that cannot be expressed in ReScript (such as keywords).
1479+
1480+It is also possible to map a ReScript record to a JavaScript array by passing indices to the `@as` decorator:
1481+
1482+<CodeTab labels={["ReScript", "JS Output"]}>
1483+
1484+```res
1485+type t = {
1486+ @as("0") foo: int,
1487+ @as("1") bar: string,
1488+}
1489+
1490+let value = {foo: 7, bar: "baz"}
1491+```
1492+
1493+```js
1494+let value = [7, "baz"];
1495+
1496+export { value };
1497+```
1498+
1499+</CodeTab>
1500+
1501+### Bind Using ReScript Object
1502+
1503+Alternatively, you can use [ReScript object](./object.mdx) to model a JS object too:
1504+
1505+<CodeTab labels={["ReScript", "JS Output"]}>
1506+
1507+```res
1508+type person = {
1509+ "name": string,
1510+ "friends": array<string>,
1511+ "age": int,
1512+}
1513+
1514+@module("MySchool") external john: person = "john"
1515+
1516+let johnName = john["name"]
1517+```
1518+
1519+```js
1520+import * as MySchool from "MySchool";
1521+
1522+let johnName = MySchool.john.name;
1523+
1524+export { johnName };
1525+```
1526+
1527+</CodeTab>
1528+
1529+### Bind Using Special Getter and Setter Attributes
1530+
1531+Alternatively, you can use `get` and `set` to bind to individual fields of a JS object:
1532+
1533+<CodeTab labels={["ReScript", "JS Output"]}>
1534+
1535+```res
1536+type textarea
1537+@set external setName: (textarea, string) => unit = "name"
1538+@get external getName: textarea => string = "name"
1539+```
1540+
1541+```js
1542+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
1543+```
1544+
1545+</CodeTab>
1546+
1547+You can also use `get_index` and `set_index` to access a dynamic property or an index:
1548+
1549+<CodeTab labels={["ReScript", "JS Output"]}>
1550+
1551+```res
1552+type t
1553+@new external create: int => t = "Int32Array"
1554+@get_index external get: (t, int) => int = ""
1555+@set_index external set: (t, int, int) => unit = ""
1556+
1557+let i32arr = create(3)
1558+i32arr->set(0, 42)
1559+Console.log(i32arr->get(0))
1560+```
1561+
1562+```js
1563+let i32arr = new Int32Array(3);
1564+
1565+i32arr[0] = 42;
1566+
1567+console.log(i32arr[0]);
1568+
1569+export { i32arr };
1570+```
1571+
1572+</CodeTab>
1573+
1574+## Bind to Hash Map-like JS Object
1575+
1576+If your JavaScript object:
1577+
1578+- might or might not add/remove keys
1579+- contains only values that are of the same type
1580+
1581+Then it's not really an object, it's a hash map. Use [Dict](/docs/manual/api/stdlib/dict), which contains operations like `get`, `set`, etc. and cleanly compiles to a JavaScript object still.
1582+
1583+## Bind to a JS Object That's a Class
1584+
1585+Use `new` to emulate e.g. `new Date()`:
1586+
1587+<CodeTab labels={["ReScript", "JS Output"]}>
1588+
1589+```res
1590+type t
1591+@new external createDate: unit => t = "Date"
1592+
1593+let date = createDate()
1594+```
1595+
1596+```js
1597+let date = new Date();
1598+
1599+export { date };
1600+```
1601+
1602+</CodeTab>
1603+
1604+You can chain `new` and `module` if the JS module you're importing is itself a class:
1605+
1606+<CodeTab labels={["ReScript", "JS Output"]}>
1607+
1608+```res
1609+type t
1610+@new @module external book: unit => t = "Book"
1611+let myBook = book()
1612+```
1613+
1614+```js
1615+import * as Book from "Book";
1616+
1617+let myBook = new Book();
1618+
1619+export { myBook };
1620+```
1621+
1622+</CodeTab>
1623+
1624+---
1625+title: "Configuration Schema"
1626+metaTitle: "Build System Configuration Schema"
1627+description: "Schema exploration widget for the ReScript configuration file"
1628+canonical: "/docs/manual/build-configuration-schema"
1629+section: "Build System"
1630+order: 3
1631+---
1632+
1633+<Suspense>
1634+ <Docson tag="master" />
1635+</Suspense>
1636+
1637+---
1638+title: "Configuration"
1639+metaTitle: "Build System Configuration"
1640+description: "Details about the configuration of the ReScript build system (rescript.json)"
1641+canonical: "/docs/manual/build-configuration"
1642+section: "Build System"
1643+order: 2
1644+---
1645+
1646+# Configuration
1647+
1648+`rescript.json` is the single, mandatory build meta file needed for `rescript`.
1649+
1650+**The complete configuration schema is [here](./build-configuration-schema.mdx)**. We'll _non-exhaustively_ highlight the important parts in prose below.
1651+
1652+## name, namespace
1653+
1654+`name` is the name of the library, used as its "namespace". You can activate namespacing through `"namespace": true` in your `rescript.json`. Namespacing is almost **mandatory**; we haven't turned it on by default yet to preserve backward-compatibility.
1655+
1656+**Explanation**: by default, your files, once used as a third-party dependency, are available globally to the consumer. E.g. if you have a `Util.res` and the consumer also has a file of the same name, they will clash. Turning on `namespace` avoids this by wrapping all your own project's files into an extra module layer; instead of a global `Util` module, the consumer will see you as `MyProject.Util`. **The namespacing affects your consumers, not yourself**.
1657+
1658+Aka, in ReScript, "namespace" is just a fancy term for an auto-generated module that wraps all your project's files (efficiently and correctly, of course!) for third-party consumption.
1659+
1660+We don't do folder-level namespacing for your own project; all your own file names must be unique. This is a constraint that enables several features such as fast search and easier project reorganization.
1661+
1662+**Note**: the `rescript.json` `name` should be the same as the `package.json` `name`, to avoid confusing corner-cases. However, this means that you can't use a camelCased names such as `MyProject`, since `package.json` and npm forbid you to do so (some file systems are case-insensitive). To have the namespace/module as `MyProject`, write `"name": "my-project"`. ReScript will turn that into the camelCased name correctly.
1663+
1664+**Note on custom namespacing**: if for some reason, you need a namespace that is different from what your `name` will produce, you can directly send a string to the `namespace` option. For example, if your package is a binding named `bs-some-thing`, you can use `"namespace": "some-thing"` to get `SomeThing` namespace instead of `BsSomeThing`.
1665+
1666+## sources
1667+
1668+Your source files need to be specified explicitly (we don't want to accidentally drill down into some unrelated directories). Examples:
1669+
1670+```json
1671+{
1672+ "sources": ["src", "examples"]
1673+}
1674+```
1675+
1676+```json
1677+{
1678+ "sources": {
1679+ "dir": "src",
1680+ "subdirs": ["page"]
1681+ }
1682+}
1683+```
1684+
1685+```json
1686+{
1687+ "sources": [
1688+ "examples",
1689+ {
1690+ "dir": "src",
1691+ "subdirs": true // recursively builds every subdirectory
1692+ }
1693+ ]
1694+}
1695+```
1696+
1697+You can mark your directories as dev-only (for e.g. tests). These won't be built and exposed to third-parties, or even to other "dev" directories in the same project:
1698+
1699+```json
1700+{
1701+ "sources": {
1702+ "dir": "test",
1703+ "type": "dev"
1704+ }
1705+}
1706+```
1707+
1708+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.
1709+Here, the file `src/MyMainModule.res` is exposed to outside consumers, while all other files are private.
1710+
1711+```json
1712+{
1713+ "sources": {
1714+ "dir": "src",
1715+ "public": ["MyMainModule"]
1716+ }
1717+}
1718+```
1719+
1720+## dependencies, dev-dependencies
1721+
1722+List of ReScript dependencies. Just like `package.json`'s dependencies, they'll be searched in `node_modules`.
1723+
1724+Note that only sources marked with `"type":"dev"` will be able to resolve modules from `dev-dependencies`.
1725+
1726+> The legacy keys `bs-dependencies` and `bs-dev-dependencies` are still accepted but deprecated.
1727+
1728+## js-post-build
1729+
1730+Hook that's invoked every time a file is recompiled. Good for JS build system interop, but please use it **sparingly**. Calling your custom command for every recompiled file slows down your build and worsens the building experience for even third-party users of your lib.
1731+
1732+Example:
1733+
1734+```json
1735+{
1736+ "js-post-build": {
1737+ "cmd": "/path/to/node ../../postProcessTheFile.js"
1738+ }
1739+}
1740+```
1741+
1742+Note that the path resolution for the command (`node` in this case) is done so:
1743+
1744+- `/myCommand` is resolved into `/myCommand`
1745+- `package/myCommand` is resolved into `node_modules/package/myCommand`
1746+- `./myCommand` is resolved into `myProjectRoot/myCommand`
1747+- `myCommand` is just called as `myCommand`, aka a globally available executable. But note that ReScript doesn't read into your shell's environment, so if you put e.g. `node`, it won't find it unless you specify an absolute path. Alternatively, add `#!/usr/local/bin/node` to the top of your script to directly call it without prepending `node`.
1748+
1749+The command itself is called from inside `lib/bs`.
1750+
1751+## jsx
1752+
1753+Controls how the compiler emits JSX and which runtime (if any) it delegates to. A minimal configuration looks like this:
1754+
1755+```json
1756+{
1757+ "jsx": {
1758+ "version": 4
1759+ }
1760+}
1761+```
1762+
1763+- `version`: JSX transform version. `4` enables the React 17+ transform and is the current and only supported option in v12.
1764+- `module`: Override the target module that receives JSX calls. Useful for [generic JSX transforms](./jsx.mdx#generic-jsx-transform-jsx-beyond-react-experimental); omit it when using the built-in React runtime.
1765+- `preserve`: When `true`, the compiler re-emits JSX syntax in the generated JavaScript so bundlers or other tooling can take over the transform later. The regenerated JSX might differ slightly from the original source but stays semantically equivalent. See [Preserve mode](./jsx.mdx#preserve-mode) for details.
1766+
1767+All fields are optional; unspecified fields fall back to the defaults mentioned above. Combine them as needed for your project's JSX runtime.
1768+
1769+## package-specs
1770+
1771+Output to either CommonJS (the default) or JavaScript module. Example:
1772+
1773+```json
1774+{
1775+ "package-specs": {
1776+ "module": "commonjs",
1777+ "in-source": true
1778+ }
1779+}
1780+```
1781+
1782+- `"module": "commonjs"` generates output as CommonJS format.
1783+- `"module": "esmodule"` generates output as JavaScript module format. Will be default value in next major.
1784+- `"in-source": true` generates output alongside source files. If you omit it, it'll generate the artifacts into `lib/js`. The output directory is not configurable otherwise.
1785+
1786+This configuration only applies to you, when you develop the project. When the project is used as a third-party library, the consumer's own `rescript.json` `package-specs` overrides the configuration here, logically.
1787+
1788+## suffix
1789+
1790+**Since 11.0**: The suffix can be freely chosen. However, we still suggest you stick to the convention and use
1791+
1792+one of the following:
1793+
1794+- `".js`
1795+- `".mjs"`
1796+- `".cjs"`
1797+- `".res.js"`
1798+- `".res.mjs"`
1799+- `".res.cjs"`
1800+
1801+### Design Decisions
1802+
1803+Generating JS files with the `.res.js` suffix means that, on the JS side, you can do `const myReScriptFile = require('./TheFile.res.js')`. The benefits:
1804+
1805+- It's immediately clear that we're dealing with a generated JS file here.
1806+- It avoids clashes with a potential `TheFile.js` file in the same folder.
1807+- 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**.
1808+
1809+## warnings
1810+
1811+Selectively turn on/off certain warnings and/or turn them into hard errors. Example:
1812+
1813+```json
1814+{
1815+ "warnings": {
1816+ "number": "-44-102",
1817+ "error": "+5"
1818+ }
1819+}
1820+```
1821+
1822+Turn off warning `44` and `102` (polymorphic comparison). Turn warning `5` (partial application whose result has function type and is ignored) into a hard error.
1823+
1824+The warning numbers are shown in the build output when they're triggered. See [Warning Numbers](./warning-numbers.mdx) for the complete list.
1825+
1826+## compiler-flags
1827+
1828+Extra flags to pass to the compiler. For advanced usages.
1829+
1830+- `-open ABC` opens the module `ABC` for each file in the project. `ABC` can either be a dependency, namespaced project or local module of the current project.
1831+
1832+> The legacy key `bsc-flags` is still accepted but deprecated.
1833+
1834+## gentypeconfig
1835+
1836+To enable genType, set `"gentypeconfig"` at top level in the project's `rescript.json`.
1837+
1838+```json
1839+{
1840+ "gentypeconfig": {
1841+ "module": "esmodule",
1842+ "moduleResolution": "node",
1843+ "generatedFileExtension": ".gen.tsx",
1844+ "debug": {
1845+ "all": false,
1846+ "basic": false
1847+ }
1848+ }
1849+}
1850+```
1851+
1852+`generatedFileExtension`: File extension used for genType generated files (defaults to `".gen.tsx"`)
1853+
1854+`module`: Module format used for the generated `*.gen.tsx` files (supports `"esmodule"` and `"commonjs"`)
1855+
1856+`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`.
1857+
1858+- `"node"`(default): Drop extensions in import paths.
1859+- `"node16"`: Use TS output's extension. This provides compatibility with projects using `"moduleResolution": "node16"` and ES Modules.
1860+- `"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`
1861+
1862+`debug`: Enable debug logs.
1863+
1864+## Environment Variables
1865+
1866+We heavily disrecommend the usage of environment variables, but for certain cases, they're justified.
1867+
1868+### Error Output Coloring: `FORCE_COLOR`
1869+
1870+This is mostly for other programmatic usage of `rescript` where outputting colors is not desired.
1871+
1872+When `FORCE_COLOR` is set to `1`: `rescript` produces color.
1873+When `FORCE_COLOR` is set to `0`: `rescript` doesn't produce color.
1874+When `FORCE_COLOR` is not set: `rescript` might or might not produce color, depending on a smart detection of where it's outputted.
1875+
1876+> Note that the underlying compiler will always be passed `-color always`. See more details in [this issue](https://github.com/rescript-lang/rescript-compiler/issues/2984#issuecomment-410669163).
1877+
1878+---
1879+title: "Setting up a monorepo"
1880+metaTitle: "Setting up a monorepo"
1881+description: "Setting up a monorepo"
1882+canonical: "/docs/manual/build-monorepo-setup"
1883+section: "Build System"
1884+order: 5
1885+---
1886+
1887+# Setting up a monorepo with ReScript
1888+
1889+**Since 12.0**
1890+
1891+> A monorepo is a single repository containing multiple separate projects, with clear relationships between them.
1892+
1893+ReScript 12.0 introduces improved support for native monorepos through the new ["Rewatch"](../../blog/reforging-build-system.mdx) build system. This guide walks you through the setup process.
1894+
1895+**Note:** This feature requires the new build system and is **not compatible** with `rescript-legacy`.
1896+
1897+## Project Structure
1898+
1899+A ReScript monorepo requires a `rescript.json` file at the repository root, plus a `rescript.json` file in each sub-project directory.
1900+Basically, the monorepo contains a root package that manages all local dependencies. Building the root package will build all its dependencies.
1901+
1902+**Important:** You also need a node_modules monorepo setup with symlinks. In practice, if you want a ReScript monorepo, you will also need an npm/yarn/pnpm/bun monorepo.
1903+
1904+A typical structure looks like this:
1905+
1906+```
1907+my-monorepo/
1908+├── rescript.json
1909+├── package.json
1910+├── node_modules/
1911+│ ├── package-1/ # symlinked
1912+│ ├── package-2/ # symlinked
1913+├── packages/
1914+│ ├── package-1/
1915+│ │ ├── rescript.json
1916+│ │ ├── package.json
1917+│ │ ├── src/
1918+│ ├── package-2/
1919+│ │ ├── rescript.json
1920+│ │ ├── package.json
1921+│ │ ├── src/
1922+│ ├── ...
1923+```
1924+
1925+## Root `rescript.json` Configuration
1926+
1927+The root `rescript.json` manages the monorepo by listing its packages.
1928+
1929+```json
1930+{
1931+ "name": "my-monorepo",
1932+ "dependencies": ["package-1", "package-2"],
1933+ "package-specs": {
1934+ "module": "esmodule",
1935+ "in-source": true
1936+ },
1937+ "suffix": ".res.mjs",
1938+ "compiler-flags": []
1939+}
1940+```
1941+
1942+The `"dependencies"` array lists the names of your packages, which must match the `"name"` fields in their respective sub-rescript.json files.
1943+When you build a package in ReScript, it will use the `"package-specs"` and `"suffix"` settings from the root package.
1944+Therefore, it is recommended to place these settings in the root `rescript.json` file and avoid specifying them in local package `rescript.json` files.
1945+
1946+**Settings from different config files:** When Rewatch builds a package within a monorepo setup, it uses these settings from the root rescript.json:
1947+
1948+- `"jsx"` (jsx_args, jsx_module_args, jsx_mode_args, jsx_preserve_args)
1949+- `"experimental"` (experimental_features_args)
1950+- `"package-specs"` (used for implementation_args)
1951+- `"suffix"` (used for package output)
1952+
1953+These settings come from the package's own rescript.json:
1954+
1955+- `"sources"` (determines which files to compile)
1956+- `"dependencies"` (package dependencies)
1957+- `"warnings"` (warning_args)
1958+- `"compiler-flags"` (bsc_flags)
1959+
1960+When the root package is built, Rewatch will look for the dependencies inside the `my-monorepo/node_modules` folder.
1961+It is expected that `package-1` and `package-2` are available there via a symlink system provided by your node_modules package manager.
1962+
1963+Note that your root rescript.json is allowed to have a `"sources"` setting.
1964+These files will be compiled as expected.
1965+
1966+## Package `rescript.json` Configuration
1967+
1968+Each nested rescript.json sets up a specific package.
1969+
1970+`packages/package-1/rescript.json`:
1971+
1972+```json
1973+{
1974+ "name": "package-1",
1975+ "sources": ["src"],
1976+ "dependencies": [],
1977+ "compiler-flags": ["-open Foobar"]
1978+}
1979+```
1980+
1981+`packages/package-2/rescript.json`:
1982+
1983+```json
1984+{
1985+ "name": "package-2",
1986+ "sources": ["src"],
1987+ "dependencies": ["package-1"],
1988+ "warnings": {
1989+ "number": "-27"
1990+ }
1991+}
1992+```
1993+
1994+In `package-1`, we show how to use special compiler flags.
1995+In `package-2`, we show how to disable warning 27 (unused variable).
1996+In both cases, the settings only apply to the package where they are specified.
1997+Defining these in the root rescript.json will not affect the packages.
1998+There is no inheritance system.
1999+
2000+Also note the dependencies array in `package-2`, which allows that package to depend on `package-1` within the monorepo.
2001+
2002+## Building the monorepo
2003+
2004+From the root directory, you can run all ReScript commands:
2005+
2006+```bash
2007+# Build all packages
2008+rescript build
2009+
2010+# Clean all packages
2011+rescript clean
2012+
2013+# Format all packages
2014+rescript format
2015+```
2016+
2017+### Building individual packages
2018+
2019+You can also run ReScript commands on individual packages instead of the entire monorepo. This is useful when you only want to work on one package.
2020+
2021+```bash
2022+# Build from the package directory
2023+cd packages/package-3
2024+rescript build
2025+rescript clean
2026+rescript format
2027+
2028+# Or run from the root directory
2029+rescript build packages/package-3
2030+rescript clean packages/package-3
2031+rescript format packages/package-3
2032+```
2033+
2034+When building a single package, ReScript will use the settings from the root rescript.json as explained in the [Root rescript.json Configuration](#root-rescriptjson-configuration) section above.
2035+
2036+### Building without a root rescript.json
2037+
2038+If your node_modules monorepo is set up with symlinks, you can build packages even without a root rescript.json:
2039+
2040+```
2041+my-monorepo/
2042+├──node_modules/
2043+│ ├── package-1/ # symlinked
2044+│ ├── package-2/ # symlinked
2045+├── package.json
2046+├── packages/
2047+│ ├── package-1/
2048+│ │ ├── rescript.json
2049+│ │ ├── package.json
2050+│ │ ├── src/
2051+│ ├── package-2/
2052+│ │ ├── rescript.json
2053+│ │ ├── package.json
2054+│ │ ├── src/
2055+│ ├── ...
2056+```
2057+
2058+Building `package-2` (which depends on `package-1`) will search up the folder structure to find `package-1`.
2059+
2060+Example:
2061+
2062+```bash
2063+rescript build ./packages/package-2
2064+```
2065+
2066+Internally, Rewatch will look for:
2067+
2068+- 🔴 `my-monorepo/packages/package-2/node_modules/package-1`
2069+- 🔴 `my-monorepo/packages/node_modules/package-1`
2070+- ✅ `my-monorepo/node_modules/package-1`
2071+
2072+This only happens as a last resort if `package-1` is not listed as a (dev-)dependency in a parent `rescript.json`.
2073+
2074+## Troubleshooting
2075+
2076+If you're having issues with your monorepo setup, you can use the `-v` flag during build to see what Rewatch detected as the project context:
2077+
2078+```bash
2079+rescript build -v
2080+```
2081+
2082+This will show you detailed information about how Rewatch is interpreting your project structure and which configuration files it's using.
2083+
2084+## Recommendation
2085+
2086+**The ReScript team strongly recommends using a root `rescript.json` file when setting up monorepos.** While it's technically possible to build packages without one (as shown in the section above), having a root configuration file provides several benefits:
2087+
2088+- **Consistent settings** across all packages (jsx, experimental features, package-specs, suffix)
2089+- **Simplified dependency management** through the root dependencies array
2090+- **Better developer experience** with unified build commands from the root
2091+- **Easier maintenance** and configuration updates across the entire monorepo
2092+
2093+The root `rescript.json` approach is the intended and supported way to work with ReScript monorepos.
2094+
2095+---
2096+title: "Overview"
2097+metaTitle: "Build System Overview"
2098+description: "Documentation about the ReScript build system and its toolchain"
2099+canonical: "/docs/manual/build-overview"
2100+section: "Build System"
2101+order: 1
2102+---
2103+
2104+# Build System Overview
2105+
2106+ReScript comes with a build system, [`rescript`](https://www.npmjs.com/package/rescript), that's fast, lean and used as the authoritative build system of the community.
2107+
2108+Every ReScript project needs a build description file, `rescript.json`.
2109+
2110+## Options
2111+
2112+See `rescript help`:
2113+
2114+```
2115+❯ rescript help
2116+Usage: rescript <options> <subcommand>
2117+
2118+`rescript` is equivalent to `rescript build`
2119+
2120+Options:
2121+ -v, -version display version number
2122+ -h, -help display help
2123+
2124+Subcommands:
2125+ build
2126+ clean
2127+ format
2128+ convert
2129+ dump
2130+ help
2131+
2132+Run `rescript <subcommand> -h` for subcommand help. Examples:
2133+ rescript build -h
2134+ rescript format -h
2135+```
2136+
2137+## Build Project
2138+
2139+Each build will create build artifacts from your project's source files.
2140+
2141+**To build a project (including its dependencies)**, run:
2142+
2143+```sh
2144+rescript
2145+```
2146+
2147+Which is an alias for `rescript build`.
2148+
2149+To keep a build watcher, run:
2150+
2151+```sh
2152+rescript -w
2153+```
2154+
2155+Any new file change will be picked up and the build will re-run.
2156+
2157+**Note**: third-party libraries in `node_modules` aren't watched, as doing so may exceed the node.js watcher count limit.
2158+
2159+For monorepo setup in ReScript 12+, see [Setting up a monorepo](./build-monorepo-setup.mdx).
2160+
2161+## Clean Project
2162+
2163+If you ever get into a stale build for edge-case reasons, use:
2164+
2165+```sh
2166+rescript clean
2167+```
2168+
2169+## Compile with stricter errors in CI
2170+
2171+**Since 11.1**
2172+
2173+You may want to compile your project with stricter rules for production, than when developing. With the `-warn-error` build flag, this can easily be done, for instance in a continuous integration script. E.g.:
2174+
2175+```sh
2176+rescript -warn-error +110
2177+```
2178+
2179+Here, warning number 110, which is triggered when a [`%todo`](../../syntax-lookup/extension_todo.mdx) has been found, gets promoted to an error. The full list of warning numbers can be found [here](./warning-numbers.mdx).
2180+
2181+---
2182+title: "Performance"
2183+metaTitle: "Build Performance"
2184+description: "ReScript build performance and measuring tools"
2185+canonical: "/docs/manual/build-performance"
2186+section: "Build System"
2187+order: 7
2188+---
2189+
2190+# Build Performance
2191+
2192+ReScript considers performance at install time, build time and run time as a serious feature; it's one of those things you don't notice until you realize it's missing.
2193+
2194+## Profile Your Build
2195+
2196+Sometime your build can be slow due to some confused infra setups. We provide an interactive visualization of your build's performance via `bstracing`:
2197+
2198+```sh
2199+./node_modules/.bin/bstracing
2200+```
2201+
2202+Run the above command at your ReScript project's root; it'll spit out a JSON file you can drag and drop into `chrome://tracing`.
2203+
2204+<Image
2205+ withShadow={true}
2206+ src="/img/bstracing.avif"
2207+ className="w-auto mx-auto md:mx-auto"
2208+ caption="Screenshot of bstracing result"
2209+/>
2210+
2211+## Under the Hood
2212+
2213+ReScript itself uses a build system under the hood, called [Ninja](https://ninja-build.org). Ninja is like Make, but cross-platform, minimal, focuses on perf and destined to be more of a low-level building block than a full-blown build system. In this regard, Ninja's a great implementation detail for `rescript`.
2214+
2215+ReScript reads into `rescript.json` and generates the Ninja build file in `lib/bs`. The file contains the low-level compiler commands, namespacing rules, intermediate artifacts generation & others. It then runs `ninja` for the actual build.
2216+
2217+## The JS Wrapper
2218+
2219+`rescript` itself is a Node.js wrapper which takes care of some miscellaneous tasks, plus the watcher. The lower-level, watcher-less, fast native `rescript` is called `rescript.exe`. It's located at `node_modules/rescript/{your-platform}/rescript.exe`.
2220+
2221+If you don't need the watcher, you can run said `rescript.exe`. This side-steps Node.js' long startup time, which can be in the order of `100ms`. Our editor plugin finds and uses this native `rescript.exe` for better performance.
2222+
2223+## Numbers
2224+
2225+Raw `rescript.exe` build on a small project should be around `70ms`. This doubles when you use the JS `rescript` wrapper which comes with a watcher, which is practically faster since you don't manually run the build at every change (though you should opt for the raw `rescript.exe` for programmatic usage, e.g. inserting rescript into your existing JS build pipeline).
2226+
2227+No-op build (when no file's changed) should be around `15ms`. Incremental rebuild (described soon) of a single file in a project is around `70ms` too.
2228+
2229+Cleaning the artifacts should be instantaneous.
2230+
2231+### Extreme Test
2232+
2233+We've stress-tested `rescript.exe` on a big project of 10,000 files (2 directories, 5000 files each, first 5000 no dependencies, last 5000 10 dependencies on files from the former directory) using https://github.com/rescript-lang/build-benchmark, on a Retina Macbook Pro Early 2015 (3.1 GHz Intel Core i7).
2234+
2235+{/* TODO: better repro */}
2236+
2237+- No-op build of 10k files: `800ms` (the minimum amount of time required to check the mtimes of 10k files).
2238+- Clean build: \<3 minutes.
2239+- Incremental build: depends on the number of the dependents of the file. No dependent means `1s`.
2240+
2241+### Stability
2242+
2243+`rescript` is a file-based build system. We don't do in-memory build, even if that speeds up the build a lot. In-memory builds risk memory leaks, out-of-memory errors, corrupt halfway build and others. Our watcher mode stays open for days or months with no leak.
2244+
2245+The watcher is also just a thin file watcher that calls `rescript.exe`. We don't like babysitting daemon processes.
2246+
2247+## Incrementality & Correctness
2248+
2249+ReScript doesn't take whole seconds to run every time. The bulk of the build performance comes from incremental build, aka re-building a previously built project when a few files changed.
2250+
2251+In short, thanks to our compiler and the build system's architecture, we're able to **only build what's needed**. If `MyFile.res` isn't changed, it isn't recompiled. Renaming or moving files is handled automatically, with no stale builds.
2252+
2253+## Speed Up Incremental Build
2254+
2255+ReScript uses the concept of interface files (`.resi`) (or, equivalently, [module signatures](./module.mdx#signatures)). Exposing only what you need naturally speeds up incremental builds. E.g. if you change a `.res` file whose corresponding `.resi` file doesn't expose the changed part, then you've reduced the amount of dependent files you have to rebuild.
2256+
2257+## Programmatic Usage
2258+
2259+Unfortunately, JS build systems are usually the bottleneck for building a JS project nowadays. Having parts of the build blazingly fast doesn't matter much if the rest of the build takes seconds or literally minutes. Here are a few suggestions:
2260+
2261+- Convert more files into ReScript =). Fewer files going through fewer parts of the JS pipeline helps a ton.
2262+- Careful with bringing in more dependencies: libraries, syntax transforms (e.g. the unofficially supported PPX), build step loaders, etc. The bulk of these dragging down the editing & building experience might out-weight the API benefits they provide.
2263+
2264+## Hot Reloading
2265+
2266+Hot reloading refers to maintaining a dev server and listening to file changes in a way that allows the server to pipe some delta changes right into the currently running browser page. This provides a relatively fast iteration workflow while working in specific frameworks.
2267+
2268+However, hot reloading is fragile by nature, and counts on the occasional inconsistencies (bad state, bad eval, etc.) and the heavy devserver setup/config being less of a hassle than the benefits it provides. We err on the side of caution and stability in general, and decided not to provide a built-in hot reloading _yet_. **Note**: you can still use the hot reloading facility provided by your JS build pipeline.
2269+
2270+---
2271+title: "If-Else & Loops"
2272+description: "If, else, ternary, for, and while"
2273+canonical: "/docs/manual/control-flow"
2274+section: "Language Features"
2275+order: 14
2276+---
2277+
2278+# If-Else & Loops
2279+
2280+ReScript supports `if`, `else`, ternary expression (`a ? b : c`), `for` and `while`.
2281+
2282+The `switch` pattern supports a default case. Read more about [pattern-matching & destructuring](./pattern-matching-destructuring.mdx).
2283+
2284+## If-Else & Ternary
2285+
2286+ReScript's `if` is an expression; it evaluates to its body's content:
2287+
2288+<CodeTab labels={["ReScript", "JS Output"]}>
2289+
2290+```res nocheck
2291+let message = if isMorning {
2292+ "Good morning!"
2293+} else {
2294+ "Hello!"
2295+}
2296+```
2297+
2298+```js
2299+var message = isMorning ? "Good morning!" : "Hello!";
2300+```
2301+
2302+</CodeTab>
2303+
2304+**Note:** an `if-else` expression without the final `else` branch implicitly gives `()` (aka the `unit` type). So this:
2305+
2306+<CodeTab labels={["ReScript", "JS Output"]}>
2307+
2308+```res nocheck
2309+if showMenu {
2310+ displayMenu()
2311+}
2312+```
2313+
2314+```js
2315+if (showMenu) {
2316+ displayMenu();
2317+}
2318+```
2319+
2320+</CodeTab>
2321+
2322+is basically the same as:
2323+
2324+<CodeTab labels={["ReScript", "JS Output"]}>
2325+
2326+```res nocheck
2327+if showMenu {
2328+ displayMenu()
2329+} else {
2330+ ()
2331+}
2332+```
2333+
2334+```js
2335+if (showMenu) {
2336+ displayMenu();
2337+}
2338+```
2339+
2340+</CodeTab>
2341+
2342+Here's another way to look at it. This is clearly wrong:
2343+
2344+```res nocheck
2345+let result = if showMenu {
2346+ 1 + 2
2347+}
2348+```
2349+
2350+It'll give a type error, saying basically that the implicit `else` branch has the type `unit` while the `if` branch has type `int`. Intuitively, this makes sense: what would `result`'s value be, if `showMenu` was `false`?
2351+
2352+We also have ternary sugar, but **we encourage you to prefer if-else when possible**.
2353+
2354+<CodeTab labels={["ReScript", "JS Output"]}>
2355+
2356+```res nocheck
2357+let message = isMorning ? "Good morning!" : "Hello!"
2358+```
2359+
2360+```js
2361+var message = isMorning ? "Good morning!" : "Hello!";
2362+```
2363+
2364+</CodeTab>
2365+
2366+`if-else` and ternary are often replaced by [pattern matching](./pattern-matching-destructuring.mdx), which handles a wide range of conditional logic more expressively.
2367+
2368+## For Loops
2369+
2370+For loops iterate from a starting value up to (and including) the ending value.
2371+
2372+<CodeTab labels={["ReScript", "JS Output"]}>
2373+
2374+```res nocheck
2375+for i in startValueInclusive to endValueInclusive {
2376+ Console.log(i)
2377+}
2378+```
2379+
2380+```js
2381+for (var i = startValueInclusive; i <= endValueInclusive; ++i) {
2382+ console.log(i);
2383+}
2384+```
2385+
2386+</CodeTab>
2387+
2388+<CodeTab labels={["ReScript", "JS Output"]}>
2389+
2390+```res nocheck
2391+// prints: 1 2 3, one per line
2392+for x in 1 to 3 {
2393+ Console.log(x)
2394+}
2395+```
2396+
2397+```js
2398+for (let x = 1; x <= 3; ++x) {
2399+ console.log(x);
2400+}
2401+```
2402+
2403+</CodeTab>
2404+
2405+You can make the `for` loop count in the opposite direction by using `downto`.
2406+
2407+<CodeTab labels={["ReScript", "JS Output"]}>
2408+
2409+```res nocheck
2410+for i in startValueInclusive downto endValueInclusive {
2411+ Console.log(i)
2412+}
2413+```
2414+
2415+```js
2416+for (var i = startValueInclusive; i >= endValueInclusive; --i) {
2417+ console.log(i);
2418+}
2419+```
2420+
2421+</CodeTab>
2422+
2423+<CodeTab labels={["ReScript", "JS Output"]}>
2424+
2425+```res nocheck
2426+// prints: 3 2 1, one per line
2427+for x in 3 downto 1 {
2428+ Console.log(x)
2429+}
2430+```
2431+
2432+```js
2433+for (let x = 3; x >= 1; --x) {
2434+ console.log(x);
2435+}
2436+```
2437+
2438+</CodeTab>
2439+
2440+## While Loops
2441+
2442+While loops execute its body code block while its condition is true.
2443+
2444+<CodeTab labels={["ReScript", "JS Output"]}>
2445+
2446+```res nocheck
2447+while testCondition {
2448+ // body here
2449+}
2450+```
2451+
2452+```js
2453+while (testCondition) {
2454+ // body here
2455+}
2456+```
2457+
2458+</CodeTab>
2459+
2460+### Tips & Tricks
2461+
2462+There's no loop-breaking `break` keyword (nor early `return` from functions, for that matter) in ReScript. However, we can break out of a while loop easily through using a [mutable binding](./mutation.mdx).
2463+
2464+<CodeTab labels={["ReScript", "JS Output"]}>
2465+
2466+```res nocheck
2467+let break = ref(false)
2468+
2469+while !break.contents {
2470+ if Math.random() > 0.3 {
2471+ break := true
2472+ } else {
2473+ Console.log("Still running")
2474+ }
2475+}
2476+```
2477+
2478+```js
2479+let $$break = {
2480+ contents: false,
2481+};
2482+
2483+while (!$$break.contents) {
2484+ if (Math.random() > 0.3) {
2485+ $$break.contents = true;
2486+ } else {
2487+ console.log("Still running");
2488+ }
2489+}
2490+
2491+export { $$break };
2492+```
2493+
2494+</CodeTab>
2495+
2496+---
2497+title: "Converting from JS"
2498+description: "How to convert to ReScript with an existing JS codebase"
2499+canonical: "/docs/manual/converting-from-js"
2500+section: "Guides"
2501+order: 1
2502+---
2503+
2504+# Converting from JS
2505+
2506+If you want a quick syntax guide before starting a migration, see [ReScript for JavaScript Developers](./rescript-for-javascript-developers.mdx).
2507+
2508+ReScript offers a unique project conversion methodology which:
2509+
2510+- Ensures minimal disruption to your teammates (very important!).
2511+- Remove the typical friction of verifying conversion's correctness and performance guarantees.
2512+- Doesn't require pre-made binding libraries. You can write bindings directly for any JavaScript API.
2513+
2514+## Step 1: Install ReScript
2515+
2516+Run `npm install rescript` on your project, then imitate our [New Project](./installation.mdx#new-project) workflow by adding a `rescript.json` at the root. Then start `npx rescript -w`.
2517+
2518+## Step 2: Copy Paste the Entire JS File
2519+
2520+Let's work on converting a file called `src/main.js`.
2521+
2522+```js
2523+const school = require("school");
2524+
2525+const defaultId = 10;
2526+
2527+function queryResult(usePayload, payload) {
2528+ if (usePayload) {
2529+ return payload.student;
2530+ } else {
2531+ return school.getStudentById(defaultId);
2532+ }
2533+}
2534+```
2535+
2536+First, copy the entire file content over to a new file called `src/Main.res` by using our [`%%raw` JS embedding trick](./embed-raw-javascript.mdx):
2537+
2538+<CodeTab labels={["ReScript", "JS Output"]}>
2539+
2540+```res
2541+%%raw(`
2542+const school = require('school');
2543+
2544+const defaultId = 10;
2545+
2546+function queryResult(usePayload, payload) {
2547+ if (usePayload) {
2548+ return payload.student;
2549+ } else {
2550+ return school.getStudentById(defaultId);
2551+ }
2552+}
2553+`)
2554+```
2555+
2556+```js
2557+const school = require("school");
2558+
2559+const defaultId = 10;
2560+
2561+function queryResult(usePayload, payload) {
2562+ if (usePayload) {
2563+ return payload.student;
2564+ } else {
2565+ return school.getStudentById(defaultId);
2566+ }
2567+}
2568+```
2569+
2570+</CodeTab>
2571+
2572+Add this file to `rescript.json`:
2573+
2574+```json
2575+ "sources": {
2576+ "dir" : "src",
2577+ "subdirs" : true
2578+ },
2579+```
2580+
2581+Open an editor tab for `src/Main.res.js`. Do a command-line `diff -u src/main.js src/Main.res.js`. Aside from whitespaces, you should see only minimal, trivial differences. You're already a third of the way done!
2582+
2583+**Always make sure** that at each step, you keep the ReScript output `.res.js` file open to compare against the existing JavaScript file. Our compilation output is very close to your hand-written JavaScript; you can simply eye the difference to catch conversion bugs!
2584+
2585+## Step 3: Extract Parts into Idiomatic ReScript
2586+
2587+Let's turn the `defaultId` variable into a ReScript let-binding:
2588+
2589+<CodeTab labels={["ReScript", "JS Output"]}>
2590+
2591+```res
2592+let defaultId = 10
2593+
2594+%%raw(`
2595+const school = require('school');
2596+
2597+function queryResult(usePayload, payload) {
2598+ if (usePayload) {
2599+ return payload.student;
2600+ } else {
2601+ return school.getStudentById(defaultId);
2602+ }
2603+}
2604+`)
2605+```
2606+
2607+```js
2608+const school = require("school");
2609+
2610+function queryResult(usePayload, payload) {
2611+ if (usePayload) {
2612+ return payload.student;
2613+ } else {
2614+ return school.getStudentById(defaultId);
2615+ }
2616+}
2617+let defaultId = 10;
2618+
2619+export { defaultId };
2620+```
2621+
2622+</CodeTab>
2623+
2624+Check the output. Diff it. Code still works. Moving on! Extract the function:
2625+
2626+<CodeTab labels={["ReScript", "JS Output"]}>
2627+
2628+```res nocheck
2629+%%raw(`
2630+const school = require('school');
2631+`)
2632+
2633+let defaultId = 10
2634+
2635+let queryResult = (usePayload, payload) => {
2636+ if usePayload {
2637+ payload.student
2638+ } else {
2639+ school.getStudentById(defaultId)
2640+ }
2641+}
2642+```
2643+
2644+```js
2645+
2646+```
2647+
2648+</CodeTab>
2649+
2650+Format the code: `./node_modules/.bin/rescript format src/Main.res`.
2651+
2652+We have a type error: "The record field student can't be found". That's fine! **Always ensure your code is syntactically valid first**. Fixing type errors comes later.
2653+
2654+## Step 4: Add externals, Fix Types
2655+
2656+The previous type error is caused by `payload`'s record declaration (which supposedly contains the field `student`) not being found. Since we're trying to convert as quickly as possible, let's use our [object](./object.mdx) feature to avoid needing type declaration ceremonies:
2657+
2658+<CodeTab labels={["ReScript", "JS Output"]}>
2659+
2660+```res nocheck
2661+%%raw(`
2662+const school = require('school');
2663+`)
2664+
2665+let defaultId = 10
2666+
2667+let queryResult = (usePayload, payload) => {
2668+ if usePayload {
2669+ payload["student"]
2670+ } else {
2671+ school["getStudentById"](defaultId)
2672+ }
2673+}
2674+```
2675+
2676+```js
2677+
2678+```
2679+
2680+</CodeTab>
2681+
2682+Now this triggers the next type error, that `school` isn't found. Let's use [`external`](./external.mdx) to bind to that module:
2683+
2684+<CodeTab labels={["ReScript", "JS Output"]}>
2685+
2686+```res
2687+@module external school: 'whatever = "school"
2688+
2689+let defaultId = 10
2690+
2691+let queryResult = (usePayload, payload) => {
2692+ if usePayload {
2693+ payload["student"]
2694+ } else {
2695+ school["getStudentById"](defaultId)
2696+ }
2697+}
2698+```
2699+
2700+```js
2701+import * as School from "school";
2702+
2703+function queryResult(usePayload, payload) {
2704+ if (usePayload) {
2705+ return payload.student;
2706+ } else {
2707+ return School.getStudentById(10);
2708+ }
2709+}
2710+
2711+let defaultId = 10;
2712+
2713+export { defaultId, queryResult };
2714+```
2715+
2716+</CodeTab>
2717+
2718+We hurrily typed `school` as a polymorphic `'whatever` and let its type be inferred by its usage below. The inference is technically correct, but within the context of bringing it a value from JavaScript, slightly dangerous. This is just the interop trick we've shown in the [`external`](./external.mdx) page.
2719+
2720+Anyway, the file passes the type checker again. Check the `.res.js` output, diff with the original `.js`; we've now converted a file over to ReScript!
2721+
2722+Now, you can delete the original, hand-written `main.js` file, and grep the files importing `main.js` and change them to importing `Main.res.js`.
2723+
2724+## (Optional) Step 5: Cleanup
2725+
2726+If you prefer more advanced, rigidly typed `payload` and `school`, feel free to do so:
2727+
2728+<CodeTab labels={["ReScript", "JS Output"]}>
2729+
2730+```res
2731+type school
2732+type student
2733+type payload = {
2734+ student: student
2735+}
2736+
2737+@module external school: school = "school"
2738+@send external getStudentById: (school, int) => student = "getStudentById"
2739+
2740+let defaultId = 10
2741+
2742+let queryResult = (usePayload, payload) => {
2743+ if usePayload {
2744+ payload.student
2745+ } else {
2746+ school->getStudentById(defaultId)
2747+ }
2748+}
2749+```
2750+
2751+```js
2752+import * as School from "school";
2753+
2754+function queryResult(usePayload, payload) {
2755+ if (usePayload) {
2756+ return payload.student;
2757+ } else {
2758+ return School.getStudentById(10);
2759+ }
2760+}
2761+
2762+let defaultId = 10;
2763+
2764+export { defaultId, queryResult };
2765+```
2766+
2767+</CodeTab>
2768+
2769+We've:
2770+
2771+- introduced an opaque types for `school` and `student` to prevent misuse of their values
2772+- typed the payload as a record with only the `student` field
2773+- typed `getStudentById` as the sole method of `student`
2774+
2775+Check that the `.res.js` output didn't change. How rigidly to type your JavaScript code is up to you; we recommend not typing them too elaborately; it's sometime an endless chase, and produces diminishing returns, especially considering that the elaborate-ness might turn off your potential teammates.
2776+
2777+## Tips & Tricks
2778+
2779+In the same vein of idea, **resist the urge to write your own wrapper functions for the JS code you're converting**. Use [`external`s](./external.mdx), which are guaranteed to be erased in the output. And avoid trying to take the occasion to convert JS data structures into ReScript-specific data structures like variant or list. **This isn't the time for that**.
2780+
2781+The moment you produce extra conversion code in the output, your skeptical teammate's mental model might switch from "I recognize this output" to "this conversion might be introducing more problems than it solves. Why are we testing ReScript again?". Then you've lost.
2782+
2783+## Conclusion
2784+
2785+- Paste the JS code into a new ReScript file as embedded raw JS code.
2786+- Compile and keep the output file open. Check and diff against original JS file. Free regression tests.
2787+- Always make sure your file is syntactically valid. Don't worry about fixing types before that.
2788+- (Ab)use [object](./object.mdx) accesses to quickly convert things over.
2789+- Optionally clean up the types for robustness.
2790+- Don't go overboard and turn off your boss and fellow teammates.
2791+- Proudly display that you've conserved the semantics and performance characteristics during the conversion by showing your teammates the eerily familiar output.
2792+- Get promoted for introducing a new technology the safer, mature way.
2793+
2794+---
2795+title: "Dictionary"
2796+description: "Dictionary data structure in ReScript"
2797+canonical: "/docs/manual/dict"
2798+section: "Language Features"
2799+order: 8
2800+---
2801+
2802+# Dictionary
2803+
2804+ReScript has first class support for dictionaries. Dictionaries are mutable objects with string keys, where all values must have the same type. Dicts compile to regular JavaScript objects at runtime.
2805+
2806+## Create
2807+
2808+You can create a new dictionary in a few different ways, depending on your use case.
2809+
2810+<CodeTab labels={["ReScript", "JS Output"]}>
2811+
2812+```res prelude
2813+// Using the first class dict syntax
2814+let d = dict{"A": 5, "B": 6}
2815+
2816+// Programatically via the standard library
2817+let d2 = Dict.fromArray([("A", 5), ("B", 6)])
2818+```
2819+
2820+```js
2821+let d = {
2822+ A: 5,
2823+ B: 6,
2824+};
2825+
2826+let d2 = Object.fromEntries([
2827+ ["A", 5],
2828+ ["B", 6],
2829+]);
2830+```
2831+
2832+</CodeTab>
2833+
2834+A few things to note here:
2835+
2836+- Using the first class `dict{}` syntax compiles cleanly to a JavaScript object directly
2837+- Using `Dict.fromArray` is useful when you need to create a dictionary programatically
2838+
2839+## Access
2840+
2841+You can access values from a Dictionary either via the the standard library `Dict` module functions, or using pattern matching.
2842+
2843+<CodeTab labels={["ReScript", "JS Output"]}>
2844+
2845+```res prelude
2846+let d = dict{"A": 5, "B": 6, "C": 7}
2847+
2848+// Using `Dict.get`
2849+let a = d->Dict.get("A")
2850+
2851+// Switching on the full dict
2852+let b = switch d {
2853+| dict{"B": b} => Some(b)
2854+| _ => None
2855+}
2856+
2857+// Destructuring
2858+let dict{"C": ?c} = d
2859+```
2860+
2861+```js
2862+let d = {
2863+ A: 5,
2864+ B: 6,
2865+ C: 7,
2866+};
2867+
2868+let a = d["A"];
2869+
2870+let b = d.B;
2871+
2872+let b$1 = b !== undefined ? b : undefined;
2873+
2874+let c = d.C;
2875+```
2876+
2877+</CodeTab>
2878+
2879+> In the Destructuring example, we're using the `?` optional pattern match syntax to pull out the `C` key value as an optional, regardless of if the dict has it or not.
2880+
2881+## Pattern matching
2882+
2883+Dictionaries have first class support for pattern matching. Read more in the [dedicated guide on pattern matching and destructring in ReScript](./pattern-matching-destructuring.mdx#match-on-dictionaries).
2884+
2885+## Updating and setting values
2886+
2887+You can set and update new values on your dictionary using the `Dict.set` function. All updates are mutable.
2888+
2889+<CodeTab labels={["ReScript", "JS Output"]}>
2890+
2891+```res prelude
2892+let d = dict{"A": 5, "B": 6}
2893+
2894+d->Dict.set("C", 7)
2895+```
2896+
2897+```js
2898+let d = {
2899+ A: 5,
2900+ B: 6,
2901+};
2902+
2903+d["C"] = 7;
2904+```
2905+
2906+</CodeTab>
2907+
2908+## Advanced example: Pattern matching on JSON
2909+
2910+JSON objects are represented as dictionaries (`dict<JSON.t>`). You can leverage that fact to decode JSON in a nice way, using only language features:
2911+
2912+<CodeTab labels={["ReScript", "JS Output"]}>
2913+
2914+```res prelude
2915+type user = {
2916+ name: string,
2917+ email: string,
2918+}
2919+
2920+/** Decode JSON to a `user`. */
2921+let decodeUser = (json: JSON.t) => {
2922+ switch json {
2923+ | Object(dict{"name": JSON.String(name), "email": JSON.String(email)}) =>
2924+ Some({name, email})
2925+ | _ => None
2926+ }
2927+}
2928+
2929+```
2930+
2931+```js
2932+function decodeUser(json) {
2933+ if (typeof json !== "object" || json === null || Array.isArray(json)) {
2934+ return;
2935+ }
2936+ let name = json.name;
2937+ if (typeof name !== "string") {
2938+ return;
2939+ }
2940+ let email = json.email;
2941+ if (typeof email === "string") {
2942+ return {
2943+ name: name,
2944+ email: email,
2945+ };
2946+ }
2947+}
2948+```
2949+
2950+</CodeTab>
2951+
2952+---
2953+title: "Dead Code Analysis in ReScript"
2954+metaTitle: "Dead Code Analysis in ReScript"
2955+description: "Documentation about ReScript editor plugins and code analysis"
2956+canonical: "/docs/manual/editor-code-analysis"
2957+section: "Guides"
2958+order: 2
2959+---
2960+
2961+# Dead Code Analysis in ReScript
2962+
2963+This guide provides a detailed walkthrough on how to leverage ReScript’s powerful dead code analysis tools to maintain a clean, efficient, and distraction-free codebase.
2964+
2965+Dead code refers to code that's present in your codebase but is never executed. It can lead to:
2966+
2967+- Increased compilation times
2968+- Confusion during development
2969+- Misleading assumptions about functionality
2970+
2971+ReScript’s language design allows for accurate and efficient dead code analysis using the **ReScript Code Analyzer**, available via the official VSCode extension.
2972+
2973+### Prerequisites
2974+
2975+- ReScript VSCode extension (v1.8.2 or higher)
2976+
2977+### Activation
2978+
2979+1. Open the Command Palette: `Cmd/Ctrl + P`
2980+2. Run: `> ReScript: Start Code Analyzer`
2981+
2982+### Deactivation
2983+
2984+- Run: `> ReScript: Stop Code Analyzer`
2985+- Or click “Stop Code Analyzer” in the status bar
2986+
2987+### Result
2988+
2989+- The “Problems” pane populates with dead code warnings and suggestions.
2990+
2991+### Reactive Updates (New)
2992+
2993+Reactive dead code updates are a newer enhancement of Editor Code Analysis and require ReScript VSCode extension v1.73.9 or higher (pre-release).
2994+
2995+## Real-World Use Cases
2996+
2997+### 1. **Unused Record Fields**
2998+
2999+```rescript
3000+type useReturn = {
3001+ items: array<item>,
3002+ toggleItemChecked: string => unit, // ← Never used
3003+ setCheckedOnItem: (string, bool) => unit,
3004+ checkAll: unit => unit,
3005+ uncheckAll: unit => unit,
3006+}
3007+```
3008+
3009+Remove unused fields to simplify code.
3010+
3011+### 2. **Unused Variant Cases**
3012+
3013+```rescript
3014+type textType =
3015+ | Text(string)
3016+ | TextWithIcon({icon: React.element, text: string})
3017+ | Render(React.element) // ← Never constructed
3018+```
3019+
3020+Removing unused variants allows simplifying rendering logic.
3021+
3022+### 3. **Unused Parts of State**
3023+
3024+```rescript
3025+type validationState = Idle | Invalid | Valid
3026+
3027+type state = {
3028+ oldPassword: string,
3029+ newPassword: string,
3030+ newPasswordRepeated: string,
3031+ validationState: validationState, // ← Never read
3032+}
3033+```
3034+
3035+Old validation logic might remain after refactors—clean it up.
3036+
3037+### 4. **Unnecessary Interface Exposure**
3038+
3039+```rescript
3040+// DrilldownTarget.resi
3041+MetricParam.parse // ← Never used
3042+MetricParam.serialize // ← Never used
3043+```
3044+
3045+Keep interfaces minimal by removing unused exports.
3046+
3047+### 5. **Unused Functions**
3048+
3049+```rescript
3050+let routerUrlToPath = ... // ← Never used
3051+let routeUrlStartsWith = ... // ← Never used
3052+```
3053+
3054+Removing these often uncovers further unused logic.
3055+
3056+### 6. **Unused Components**
3057+
3058+Components never referenced in production should be removed, unless explicitly preserved.
3059+
3060+## Keeping Some Dead Code
3061+
3062+### Use `@dead` and `@live`
3063+
3064+#### `@dead`
3065+
3066+Suppresses warnings but notifies if code becomes alive again.
3067+
3068+```rescript
3069+type user = {
3070+ name: string,
3071+ @dead age: int,
3072+}
3073+```
3074+
3075+#### `@live`
3076+
3077+Permanently marks code as alive (no future warnings).
3078+
3079+```rescript
3080+@live
3081+let getUserName = user => user.name
3082+```
3083+
3084+## Configuration
3085+
3086+Add to your `rescript.json`:
3087+
3088+```json
3089+"reanalyze": {
3090+ "analysis": ["dce"],
3091+ "suppress": ["src/bindings", "src/stories", "src/routes"],
3092+ "unsuppress": [],
3093+ "transitive": false
3094+}
3095+```
3096+
3097+### Options:
3098+
3099+- **analysis**: Enables dead code analysis (`"dce"`)
3100+- **suppress**: Silences reporting for paths (still analyzes)
3101+- **unsuppress**: Re-enables reports within suppressed paths
3102+- **transitive**: Controls reporting of indirectly dead code
3103+
3104+**Recommendation:** Set `transitive: false` for incremental cleanup.
3105+
3106+## Summary
3107+
3108+ReScript’s dead code analyzer helps you:
3109+
3110+- Incrementally clean up your codebase
3111+- Avoid confusion and complexity
3112+- Improve long-term maintainability
3113+
3114+Use it regularly for the best results.
3115+
3116+---
3117+title: "Editor"
3118+metaTitle: "Editor"
3119+description: "Documentation about ReScript editor plugins and code analysis"
3120+canonical: "/docs/manual/editor-plugins"
3121+section: "Overview"
3122+order: 4
3123+---
3124+
3125+# Editor
3126+
3127+This section is about the editor plugin for ReScript. It adds syntax highlighting, autocomplete, type hints, formatting, code navigation, code analysis for `.res` and `.resi` files.
3128+
3129+## Plugins
3130+
3131+- [VSCode](https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode)
3132+- [Sublime Text](https://github.com/rescript-lang/rescript-sublime)
3133+- [Vim/Neovim](https://github.com/rescript-lang/vim-rescript)
3134+
3135+### Community Supported
3136+
3137+We don't officially support these; use them at your own risk!
3138+
3139+- [Neovim Tree-sitter](https://github.com/nkrkv/nvim-treesitter-rescript)
3140+- [IDEA](https://github.com/reasonml-editor/reasonml-idea-plugin)
3141+- [Emacs](https://github.com/jjlee/rescript-mode)
3142+
3143+## Code analysis
3144+
3145+The code analysis provides extra checks for your ReScript project, such as detecting dead code and unhandled exceptions. It's powered by [reanalyze](https://github.com/rescript-association/reanalyze), which is built into the extension — no separate install required.
3146+
3147+### How to Use
3148+
3149+- Open the command palette and run:
3150+ `ReScript: Start Code Analyzer`
3151+- Warnings like dead code will show inline in the editor.
3152+- Suppression actions are available where applicable.
3153+- To stop analysis, click **Stop Code Analyzer** in the status bar.
3154+
3155+### Configuration
3156+
3157+Add a `reanalyze` section to your `rescript.json` to control what the analyzer checks or ignores. You'll get autocomplete for config options in the editor.
3158+More details: [reanalyze configuration docs](https://github.com/rescript-association/reanalyze#configuration-via-bsconfigjson)
3159+
3160+### Exception analysis
3161+
3162+The exception analysis is designed to keep track statically of the exceptions that might be thrown at runtime. It works by issuing warnings and recognizing annotations. Warnings are issued whenever an exception is thrown and not immediately caught. Annotations are used to push warnings from he local point where the exception is thrown, to the outside context: callers of the current function.
3163+Nested functions need to be annotated separately.
3164+
3165+Instructions on how to run the exception analysis using the `-exception` and `-exception-cmt` command-line arguments, or how to add `"analysis": ["exception"]` in `rescript.json` are contained in the [reanalyze configuration docs](https://github.com/rescript-association/reanalyze#configuration-via-bsconfigjson).
3166+
3167+Here's an example, where the analysis reports a warning any time an exception is thrown, and not caught:
3168+
3169+```rescript
3170+let throws = () => throw(Not_found)
3171+```
3172+
3173+reports:
3174+
3175+```sh
3176+
3177+ Exception Analysis
3178+ File "A.res", line 1, characters 4-10
3179+ throws might throw Not_found (A.res:1:19) and is not annotated with @throws(Not_found)
3180+```
3181+
3182+No warning is reported when a `@throws` annotation is added:
3183+
3184+```rescript
3185+@throws(Not_found)
3186+let throws = () => throw(Not_found)
3187+```
3188+
3189+When a function throws multiple exceptions, a tuple annotation is used:
3190+
3191+```rescript
3192+exception A
3193+exception B
3194+
3195+@throws([A, B])
3196+let twoExceptions = (x, y) => {
3197+ if (x) {
3198+ throw(A)
3199+ }
3200+ if (y) {
3201+ throw(B)
3202+ }
3203+}
3204+```
3205+
3206+It is possible to silence the analysis by adding a `@doesNotThrow` annotation:
3207+
3208+```rescript
3209+@throws(Invalid_argument)
3210+let stringMake1 = String.make(12, ' ')
3211+
3212+// Silence only the make function
3213+let stringMake2 = (@doesNotThrow String.make)(12, ' ')
3214+
3215+// Silence the entire call (including arguments to make)
3216+let stringMake3 = @doesNotThrow String.make(12, ' ')
3217+
3218+```
3219+
3220+#### Limitations
3221+
3222+- The libraries currently modeled are limited to the standard library, Belt and Js modules. Models are currently vendored in the analysis, and are easy to add (see [`analysis/reanalyze/src/ExnLib.ml`](https://github.com/rescript-lang/rescript/blob/master/analysis/reanalyze/src/ExnLib.ml))
3223+- Generic exceptions are not understood by the analysis. For example `exn` is not recognized below (only concrete exceptions are):
3224+
3225+```rescript
3226+try (foo()) { | exn => throw(exn) }
3227+```
3228+
3229+- Uses of e.g. `List.head` are interpreted as belonging to the standard library. If you re-define `List` in the local scope, the analysis it will think it's dealing with `List` from the standard library.
3230+- There is no special support for module functions.
3231+
3232+### Guide
3233+
3234+Look - [Editor Code Analysis](./editor-code-analysis.mdx) for a more detailed guide about how to use the code analysis tool.
3235+
3236+### Caveats
3237+
3238+- For older extension versions, cross-package dead code analysis in monorepos may be limited.
3239+
3240+## Editor features
3241+
3242+Below are features and configurations of the editor tooling that might be good to know about.
3243+
3244+### Pipe completions
3245+
3246+Pipes (`->`) are a huge and important part of the ReScript language, for many reasons. Because of that, extra care has gone into the editor experience for using pipes.
3247+
3248+#### Default pipe completion rules for non-builtin types
3249+
3250+By default, using `->` will give completions from the module where the type of the expression you're piping on is defined. So, if you're piping on something of the type `SomeModule.t` (like `someValue->`) then you'll get completions for all functions defined in `SomeModule` that take the type `t` as the first unlabelled argument.
3251+
3252+#### Pipe completions for builtin types
3253+
3254+For builtin types, completion will automatically happen based on the _standard library module_ for that type. So, `array` types will get completions from the `Array` module, `string` gets completions from `String`, and so on.
3255+
3256+There is a way to enhance this behavior via configuration, described further down in this document.
3257+
3258+### Dot completion enhancements
3259+
3260+In ReScript, using a dot (`.`) normally means "access record field". The editor extends dot (`.`) to trigger completions in more scenarios beyond record field access.
3261+
3262+This behavior has the following important implications:
3263+
3264+- Improves discoverability (E.g. using a `.` will reveal important pipe completions)
3265+
3266+Below is a list of all the scenarios where using dots trigger completion in addition to the normal record field completion.
3267+
3268+#### Objects
3269+
3270+When writing a `.` on something that's a [structural object](./object.mdx), you'll get completions for those object properties. Example:
3271+
3272+```res nocheck
3273+let obj = {
3274+ "first": true,
3275+ "second": false
3276+}
3277+
3278+let x = obj.
3279+
3280+// Will give the following completions for object property access:
3281+// - ["first"]
3282+// - ["second"]
3283+```
3284+
3285+#### Pipe completions for anything
3286+
3287+When writing `.` on _anything_, the editor will try to do pipe completion for the value on the left of the `.`. Example:
3288+
3289+```res nocheck
3290+let arr = [1, 2, 3]
3291+
3292+let x = arr.
3293+
3294+// Will give the following pipe completions:
3295+// - ->Array.length
3296+// - ->Array.filter
3297+// - ->Array.map
3298+```
3299+
3300+### `@editor.completeFrom` for drawing completions from additional modules
3301+
3302+You can configure any type you have control over to draw pipe completions from additional modules, in addition to the main module where the type is defined, via the `@editor.completeFrom` decorator. This is useful in many different scenarios:
3303+
3304+- When you, for various reasons, need to have your type definition separate from its "main module". Could be because of cyclic dependencies, a need for the type to be in a recursive type definition chain, and so on.
3305+- You have separate modules with useful functions for your type but that you don't want to (or can't) include in the main module of that type.
3306+
3307+Let's look at an example:
3308+
3309+```res nocheck
3310+// Types.res
3311+// In this example types need to live separately in their own file, for various reasons
3312+type htmlInput
3313+
3314+// Utils.res
3315+module HtmlInput = {
3316+ /** Gets the HTML input value. */
3317+ @get
3318+ external value: Types.htmlInput => option<string> = "value"
3319+}
3320+```
3321+
3322+In the example above, if we try and pipe on something of the type `Types.htmlInput`, we'll get no completions because there are no functions in `Types` that take `htmlInput` as its first unlabelled argument. But, better DX would be for the editor to draw completions from our util functions for `htmlInput` in the `Utils.HtmlInput` module.
3323+
3324+With `@editor.completeFrom`, we can fix this. Let's look at an updated example:
3325+
3326+```res nocheck
3327+// Types.res
3328[email protected](Utils.HtmlInput)
3329+type htmlInput
3330+
3331+// Utils.res
3332+module HtmlInput = {
3333+ /** Gets the HTML input value. */
3334+ @get
3335+ external value: Types.htmlInput => option<string> = "value"
3336+}
3337+```
3338+
3339+Now when piping on a value of the type `Types.htmlInput`, the editor tooling will know to include relevant functions from the module `Utils.HtmlInput`, and you'll get the completions you expect, even if the functions aren't located in the same module.
3340+
3341+> You can point out multiple modules to draw completions from for a type either by repeating `@editor.completeFrom` with a single module path each time, or by passing an array with all the module paths you want to include, like `@editor.completeFrom([Utils.HtmlInput, HtmlInputUtils])`.
3342+
3343+### Configuring the editor via `editor` in `rescript.json`
3344+
3345+There's certain configuration you can do for the editor on a per project basis in `rescript.json`. Below lists all of the configuration available.
3346+
3347+#### `autocomplete` for pipe completion
3348+
3349+The `autocomplete` property of `editor` in `rescript.json` let's you map types to modules _on the project level_ that you want the editor to leverage when doing autocomplete for pipes.
3350+
3351+This is useful in scenarios like:
3352+
3353+- You have your own util module(s) for builtin types. Maybe you have an `ArrayExtra` with helpers for arrays that you want to get completions from whenever dealing with arrays.
3354+- You have your own util module(s) for types you don't control yourself (and therefore can't use `@editor.completeFrom`), like from external packages you install.
3355+
3356+To configure, you pass `autocomplete` an object where the keys are the _path to the type_ you want to target, and then an array of the path to each module you want to include for consideration for pipe completions.
3357+
3358+Let's take two examples.
3359+
3360+##### Enhancing completion for builtin types
3361+
3362+First, let's look at including our own `ArrayExtra` in all completions for `array`:
3363+
3364+```json
3365+{
3366+ "editor": {
3367+ "autocomplete": {
3368+ "array": ["ArrayExtra"]
3369+ }
3370+ }
3371+}
3372+```
3373+
3374+Now, when using pipes on arrays, you'll get completions both from the standard library array functions, and also from your own `ArrayExtra` module.
3375+
3376+```res nocheck
3377+let x = [1, 2, 3]->
3378+
3379+// Example of what completing at the pipe might look like
3380+- Array.length
3381+- Array.map
3382+- Array.filter
3383+- ArrayExtra.someArrayFn
3384+- ArrayExtra.myOtherArrayFn
3385+```
3386+
3387+**Note**: generic types like `promise.t` and `result.t` do not need any additional types in the `rescript.json`:
3388+
3389+```json
3390+"editor": {
3391+ "autocomplete": {
3392+ "promise": ["PromiseExt"],
3393+ "result": ["ResultExt"]
3394+ }
3395+}
3396+```
3397+
3398+##### Enhancing completion for non-builtin types
3399+
3400+Now, let's look at an example of when you have a non-builtin type that you don't have control over.
3401+
3402+In this example, imagine this:
3403+
3404+- We're writing an app using `fastify`
3405+- We're using an external package that provides the necessary bindings in a `Fastify` module
3406+- We've got our own extra file `FastifyExtra` that has various custom util functions that operate on the main type `Fastify.t`
3407+
3408+We now want the editor to always suggest completions from the `FastifyExtra` module, in addition to the regular completions from the main `Fastify` module.
3409+
3410+Let's configure this using the `editor.autocomplete` config in `rescript.json`:
3411+
3412+```json
3413+{
3414+ "editor": {
3415+ "autocomplete": {
3416+ "Fastify.t": ["FastifyExt"]
3417+ }
3418+ }
3419+}
3420+```
3421+
3422+Now, when using pipes on anything of type `Fastify.t`, we'll also get completions from our custom `FastifyExtra`.
3423+
3424+##### Enhancing completion for non-builtin types with namespaces
3425+
3426+When a project uses a namespace, this affects the internal representation of type names used in the `autocomplete` configuration.
3427+
3428+Consider the [geolocation](https://rescript-lang.github.io/experimental-rescript-webapi/apidocs/geolocation-api/#geolocation) type from the [Experimental WebAPI bindings](https://rescript-lang.github.io/experimental-rescript-webapi/).
3429+This project specifies in its `rescript.json`:
3430+
3431+```json
3432+{
3433+ "name": "@rescript/webapi",
3434+ "namespace": "WebAPI"
3435+}
3436+```
3437+
3438+This makes the `geolocation` type internally represented as `GeolocationAPI-WebAPI.geolocation`, where:
3439+
3440+- `GeolocationAPI` is the module name
3441+- `WebAPI` is the namespace
3442+- `geolocation` is the type name
3443+
3444+**Important**: You must use this internal representation when configuring autocomplete for namespaced types:
3445+
3446+```json
3447+{
3448+ "editor": {
3449+ "autocomplete": {
3450+ "GeolocationAPI-WebAPI.geolocation": ["GeolocationExt"]
3451+ }
3452+ }
3453+}
3454+```
3455+
3456+---
3457+title: "Embed Raw JavaScript"
3458+description: "Utility syntax to for raw JS usage in ReScript"
3459+canonical: "/docs/manual/embed-raw-javascript"
3460+section: "JavaScript Interop"
3461+order: 2
3462+---
3463+
3464+# Embed Raw JavaScript
3465+
3466+## Paste Raw JS Code
3467+
3468+First thing first. If you're ever stuck learning ReScript, remember that you can always just paste raw JavaScript code into our source file:
3469+
3470+<CodeTab labels={["ReScript", "JS Output"]}>
3471+
3472+```res
3473+%%raw(`
3474+// look ma, regular JavaScript!
3475+var message = "hello";
3476+function greet(m) {
3477+ console.log(m)
3478+}
3479+`)
3480+```
3481+
3482+```js
3483+// look ma, regular JavaScript!
3484+var message = "hello";
3485+function greet(m) {
3486+ console.log(m);
3487+}
3488+```
3489+
3490+</CodeTab>
3491+
3492+The `%%raw` special ReScript call takes your code string and pastes it as-is into the output. **You've now technically written your first ReScript file!**
3493+
3494+(The backtick syntax is a multiline string. No escaping is needed inside the string.)
3495+
3496+While `%%raw` lets you embed top-level raw JS code, `%raw` lets you embed expression-level JS code:
3497+
3498+<CodeTab labels={["ReScript", "JS Output"]}>
3499+
3500+```res
3501+let add = %raw(`
3502+ function(a, b) {
3503+ console.log("hello from raw JavaScript!");
3504+ return a + b
3505+ }
3506+`)
3507+
3508+Console.log(add(1, 2))
3509+```
3510+
3511+```js
3512+let add = function (a, b) {
3513+ console.log("hello from raw JavaScript!");
3514+ return a + b;
3515+};
3516+
3517+console.log(add(1, 2));
3518+
3519+export { add };
3520+```
3521+
3522+</CodeTab>
3523+
3524+The above code:
3525+
3526+- declared a ReScript variable `add`,
3527+- with the raw JavaScript value of a function declaration,
3528+- then called that function in ReScript.
3529+
3530+Existing JavaScript code can live inside ReScript files during migration.
3531+
3532+## Debugger
3533+
3534+You can also drop a `%debugger` expression in a body:
3535+
3536+<CodeTab labels={["ReScript", "JS Output"]}>
3537+
3538+```res
3539+let f = (x, y) => {
3540+ %debugger
3541+ x + y
3542+}
3543+```
3544+
3545+```js
3546+function f(x, y) {
3547+ debugger;
3548+ return (x + y) | 0;
3549+}
3550+
3551+export { f };
3552+```
3553+
3554+</CodeTab>
3555+
3556+Output:
3557+
3558+```js
3559+function f(x, y) {
3560+ debugger; // JavaScript developer tools will set an breakpoint and stop here
3561+ x + y;
3562+}
3563+```
3564+
3565+## Tips & Tricks
3566+
3567+Embedding raw JS snippets isn't the best way to experience ReScript, though it's also highly useful if you're just starting out. As a matter of fact, the first few ReScript projects were converted through:
3568+
3569+- pasting raw JS snippets inside a file
3570+- examining the JS output (identical to the old hand-written JS)
3571+- gradually extract a few values and functions and making sure the output still looks OK
3572+
3573+At the end, we get a fully safe, converted ReScript file whose JS output is clean enough that we can confidently assert that no new bug has been introduced during the conversion process.
3574+
3575+See the [Converting from JS](./converting-from-js.mdx) guide for a detailed walkthrough.
3576+
3577+---
3578+title: "Equality and Comparison"
3579+description: "Handling equality and comparison checks"
3580+canonical: "/docs/manual/equality-comparison"
3581+section: "Language Features"
3582+order: 28
3583+---
3584+
3585+# Equality and Comparison
3586+
3587+ReScript has shallow equality `===`, deep equality `==`, and comparison operators `>`, `>=`, `<`, and `<=`.
3588+
3589+## Shallow equality
3590+
3591+The shallow equality operator `===` compares two values and either compiles to `===` or a `bool` if the equality is known to the compiler.
3592+It behaves the same as the strict equality operator `===` in JavaScript.
3593+
3594+Using `===` will never add a runtime cost.
3595+
3596+<CodeTab labels={["ReScript", "JS Output"]}>
3597+
3598+```res
3599+let t1 = 1 === 1 // true
3600+let t2 = "foo" === "foo" // true
3601+let t3 = { "foo": "bar" } === { "foo": "bar"} // false
3602+
3603+let doStringsMatch = (s1: string, s2: string) => s1 === s2
3604+```
3605+
3606+```js
3607+let t2 = "foo" === "foo";
3608+
3609+let t3 =
3610+ {
3611+ foo: "bar",
3612+ } ===
3613+ {
3614+ foo: "bar",
3615+ };
3616+
3617+function doStringsMatch(s1, s2) {
3618+ return s1 === s2;
3619+}
3620+
3621+let t1 = true;
3622+
3623+export { t1, t2, t3, doStringsMatch };
3624+```
3625+
3626+</CodeTab>
3627+
3628+## Deep equality
3629+
3630+ReScript has the deep equality operator `==` to check deep equality of two items, which is very different from the loose equality operator like `==` in JavaScript.
3631+
3632+When using `==` in ReScript it will never compile to `==` in JavaScript,
3633+it will either compile to `===`, a runtime call to an internal function that deeply compares the equality, or a `bool` if the equality is known to the compiler.
3634+
3635+<CodeTab labels={["ReScript", "JS Output"]}>
3636+
3637+```res
3638+let t1 = 1 == 1 // true
3639+let t2 = "foo" == "foo" // true
3640+let t3 = { "foo": "bar" } == { "foo": "bar"} // true
3641+
3642+let doStringsMatch = (s1: string, s2: string) => s1 == s2
3643+```
3644+
3645+```js
3646+import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
3647+
3648+let t2 = true;
3649+
3650+let t3 = Primitive_object.equal(
3651+ {
3652+ foo: "bar",
3653+ },
3654+ {
3655+ foo: "bar",
3656+ },
3657+);
3658+
3659+function doStringsMatch(s1, s2) {
3660+ return s1 === s2;
3661+}
3662+
3663+let t1 = true;
3664+
3665+export { t1, t2, t3, doStringsMatch };
3666+```
3667+
3668+</CodeTab>
3669+
3670+`==` will compile to `===` (or a `bool` if the compiler can determine equality) when:
3671+
3672+- Comparing `string`, `char`, `int`, `float`, `bool`, or `unit`
3673+- Comparing variants or polymorphic variants that do not have constructor values
3674+
3675+`==` will compile to a runtime check for deep equality when:
3676+
3677+- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression `Re.t`
3678+- Comparing variants or polymorphic variants that have constructor values
3679+
3680+> When using `==` pay close attention to the JavaScript output if you're not sure what `==` will compile to.
3681+
3682+## Comparison
3683+
3684+ReScript has operators for comparing values that compile to the the same operator in JS, a runtime check using an internal function, or a `bool` if the equality is known to the compiler,
3685+
3686+| operator | comparison |
3687+| -------- | --------------------- |
3688+| `>` | greater than |
3689+| `>=` | greater than or equal |
3690+| `<` | less than |
3691+| `<=` | less than or equal |
3692+
3693+Comparison can be done on any type.
3694+
3695+An operator will compile to the same operator (or a `bool` if the compiler can determine equality) when:
3696+
3697+- Comparing `int`, `float`, `string`, `char`, `bool`
3698+
3699+An operator will compile to a runtime check for deep equality when:
3700+
3701+- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression (`Re.t`)
3702+- Comparing variants or polymorphic variants
3703+
3704+<CodeTab labels={["ReScript", "JS Output"]}>
3705+
3706+```res
3707+let compareInt = (a: int, b: int) => a > b
3708+let t1 = 1 > 10
3709+let compareArray = (a: array<int>, b: array<int>) => a > b
3710+let compareOptions = (a: option<float>, b: option<float>) => a < b
3711+```
3712+
3713+```js
3714+import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
3715+
3716+function compareInt(a, b) {
3717+ return a > b;
3718+}
3719+
3720+let compareArray = Primitive_object.greaterthan;
3721+
3722+let compareOptions = Primitive_object.lessthan;
3723+
3724+let t1 = false;
3725+
3726+export { compareInt, t1, compareArray, compareOptions };
3727+```
3728+
3729+</CodeTab>
3730+
3731+## Performance of runtime equality checks
3732+
3733+The runtime equality check ReScript uses is quite fast and should be adequate for almost all use cases.
3734+For small objects it can be 2x times faster than alternative deep compare functions such as Lodash's [`_.isEqual`](https://lodash.com/docs/4.17.15#isEqual).
3735+
3736+For larger objects instead of using `==` you could manually use a faster alternative such as [fast-deep-compare](https://www.npmjs.com/package/fast-deep-equal), or write a custom comparator function.
3737+
3738+[This repo](https://github.com/jderochervlk/rescript-perf) has benchmarks comparing results of different libraries compared to ReScript's built-in equality function.
3739+
3740+---
3741+title: "Exception"
3742+description: "Exceptions and exception handling in ReScript"
3743+canonical: "/docs/manual/exception"
3744+section: "Language Features"
3745+order: 19
3746+---
3747+
3748+# Exception
3749+
3750+Exceptions are just a special kind of variant, thrown in **exceptional** cases (don't abuse them!). Consider using the [`option`](./null-undefined-option.mdx) or [`result`](/docs/manual/api/stdlib/result) type for recoverable errors.
3751+
3752+You can create your own exceptions like you'd make a variant (exceptions need to be capitalized too).
3753+
3754+<CodeTab labels={["ReScript", "JS Output"]}>
3755+
3756+```res
3757+exception InputClosed(string)
3758+// later on
3759+throw(InputClosed("The stream has closed!"))
3760+```
3761+
3762+```js
3763+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
3764+
3765+let InputClosed = /* @__PURE__ */ Primitive_exceptions.create(
3766+ "_tempFile.InputClosed",
3767+);
3768+
3769+throw {
3770+ RE_EXN_ID: InputClosed,
3771+ _1: "The stream has closed!",
3772+ Error: new Error(),
3773+};
3774+
3775+export { InputClosed };
3776+```
3777+
3778+</CodeTab>
3779+
3780+## Built-in Exceptions
3781+
3782+ReScript has some built-in exceptions:
3783+
3784+### `Not_found`
3785+
3786+<CodeTab labels={["ReScript", "JS Output"]}>
3787+
3788+```res prelude
3789+let getItem = (item: int) =>
3790+ if (item === 3) {
3791+ // return the found item here
3792+ 1
3793+ } else {
3794+ throw(Not_found)
3795+ }
3796+
3797+let result =
3798+ try {
3799+ getItem(2)
3800+ } catch {
3801+ | Not_found => 0 // Default value if getItem throws
3802+ }
3803+```
3804+
3805+```js
3806+import * as Primitive_exceptions from "./stdlib/Primitive_exceptions.js";
3807+
3808+function getItem(item) {
3809+ if (item === 3) {
3810+ return 1;
3811+ }
3812+ throw {
3813+ RE_EXN_ID: "Not_found",
3814+ Error: new Error(),
3815+ };
3816+}
3817+
3818+let result;
3819+
3820+try {
3821+ result = getItem(2);
3822+} catch (raw_exn) {
3823+ let exn = Primitive_exceptions.internalToException(raw_exn);
3824+ if (exn.RE_EXN_ID === "Not_found") {
3825+ result = 0;
3826+ } else {
3827+ throw exn;
3828+ }
3829+}
3830+```
3831+
3832+</CodeTab>
3833+
3834+Note that the above is just for demonstration purposes; in reality, you'd return an `option<int>` directly from `getItem` and avoid the `try` altogether.
3835+
3836+You can directly match on exceptions _while_ getting another return value from a function:
3837+
3838+<CodeTab labels={["ReScript", "JS Output"]}>
3839+
3840+```res prelude
3841+switch list{1, 2, 3}->List.getOrThrow(4) {
3842+| item => Console.log(item)
3843+| exception Not_found => Console.log("No such item found!")
3844+}
3845+```
3846+
3847+```js
3848+import * as Stdlib_List from "./stdlib/Stdlib_List.js";
3849+import * as Primitive_exceptions from "./stdlib/Primitive_exceptions.js";
3850+
3851+let exit = 0;
3852+
3853+let item;
3854+
3855+try {
3856+ item = Stdlib_List.getExn(
3857+ {
3858+ hd: 1,
3859+ tl: {
3860+ hd: 2,
3861+ tl: {
3862+ hd: 3,
3863+ tl: /* [] */ 0,
3864+ },
3865+ },
3866+ },
3867+ 4,
3868+ );
3869+ exit = 1;
3870+} catch (raw_exn) {
3871+ let exn = Primitive_exceptions.internalToException(raw_exn);
3872+ if (exn.RE_EXN_ID === "Not_found") {
3873+ console.log("No such item found!");
3874+ } else {
3875+ throw exn;
3876+ }
3877+}
3878+
3879+if (exit === 1) {
3880+ console.log(item);
3881+}
3882+```
3883+
3884+</CodeTab>
3885+
3886+### `Invalid_argument`
3887+
3888+Used to check if argument is valid. This exception takes a string.
3889+
3890+<CodeTab labels={["ReScript", "JS Output"]}>
3891+```res
3892+let divide = (a, b) =>
3893+ if b == 0 {
3894+ throw(Invalid_argument("Denominator is zero"))
3895+ } else {
3896+ a / b
3897+ }
3898+
3899+// catch error
3900+try divide(2, 0)->Console.log catch {
3901+| Invalid_argument(msg) => Console.log(msg) // Denominator is zero
3902+}
3903+
3904+````
3905+
3906+```js
3907+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
3908+import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
3909+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
3910+
3911+function getItem(item) {
3912+ if (item === 3) {
3913+ return 1;
3914+ }
3915+ throw {
3916+ RE_EXN_ID: "Not_found",
3917+ Error: new Error()
3918+ };
3919+}
3920+
3921+let result;
3922+
3923+try {
3924+ result = getItem(2);
3925+} catch (raw_exn) {
3926+ let exn = Primitive_exceptions.internalToException(raw_exn);
3927+ if (exn.RE_EXN_ID === "Not_found") {
3928+ result = 0;
3929+ } else {
3930+ throw exn;
3931+ }
3932+}
3933+
3934+let exit = 0;
3935+
3936+let item;
3937+
3938+try {
3939+ item = Stdlib_List.getOrThrow({
3940+ hd: 1,
3941+ tl: {
3942+ hd: 2,
3943+ tl: {
3944+ hd: 3,
3945+ tl: /* [] */0
3946+ }
3947+ }
3948+ }, 4);
3949+ exit = 1;
3950+} catch (raw_exn$1) {
3951+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
3952+ if (exn$1.RE_EXN_ID === "Not_found") {
3953+ console.log("No such item found!");
3954+ } else {
3955+ throw exn$1;
3956+ }
3957+}
3958+
3959+if (exit === 1) {
3960+ console.log(item);
3961+}
3962+
3963+function divide(a, b) {
3964+ if (b === 0) {
3965+ throw {
3966+ RE_EXN_ID: "Invalid_argument",
3967+ _1: "Denominator is zero",
3968+ Error: new Error()
3969+ };
3970+ }
3971+ return Primitive_int.div(a, b);
3972+}
3973+
3974+try {
3975+ console.log(divide(2, 0));
3976+} catch (raw_msg) {
3977+ let msg = Primitive_exceptions.internalToException(raw_msg);
3978+ if (msg.RE_EXN_ID === "Invalid_argument") {
3979+ console.log(msg._1);
3980+ } else {
3981+ throw msg;
3982+ }
3983+}
3984+
3985+export {
3986+ getItem,
3987+ result,
3988+ divide,
3989+}
3990+````
3991+
3992+</CodeTab>
3993+
3994+### `Assert_failure`
3995+
3996+Thrown when you use `assert(condition)` and `condition` is false. The arguments
3997+are the location of the `assert` in the source code (file name, line number, column number).
3998+
3999+<CodeTab labels={["ReScript", "JS Output"]}>
4000+
4001+```res
4002+let decodeUser = (json: JSON.t) =>
4003+ switch json {
4004+ | Object(userDict) =>
4005+ switch (userDict->Dict.get("name"), userDict->Dict.get("age")) {
4006+ | (Some(String(name)), Some(Number(age))) => (name, age->Float.toInt)
4007+ | _ => assert(false)
4008+ }
4009+ | _ => assert(false)
4010+ }
4011+
4012+
4013+try decodeUser(%raw("{}"))->Console.log catch {
4014+| Assert_failure(loc) => Console.log(loc) // ("filename", line, col)
4015+}
4016+```
4017+
4018+```js
4019+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
4020+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4021+
4022+function getItem(item) {
4023+ if (item === 3) {
4024+ return 1;
4025+ }
4026+ throw {
4027+ RE_EXN_ID: "Not_found",
4028+ Error: new Error(),
4029+ };
4030+}
4031+
4032+let result;
4033+
4034+try {
4035+ result = getItem(2);
4036+} catch (raw_exn) {
4037+ let exn = Primitive_exceptions.internalToException(raw_exn);
4038+ if (exn.RE_EXN_ID === "Not_found") {
4039+ result = 0;
4040+ } else {
4041+ throw exn;
4042+ }
4043+}
4044+
4045+let exit = 0;
4046+
4047+let item;
4048+
4049+try {
4050+ item = Stdlib_List.getOrThrow(
4051+ {
4052+ hd: 1,
4053+ tl: {
4054+ hd: 2,
4055+ tl: {
4056+ hd: 3,
4057+ tl: /* [] */ 0,
4058+ },
4059+ },
4060+ },
4061+ 4,
4062+ );
4063+ exit = 1;
4064+} catch (raw_exn$1) {
4065+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
4066+ if (exn$1.RE_EXN_ID === "Not_found") {
4067+ console.log("No such item found!");
4068+ } else {
4069+ throw exn$1;
4070+ }
4071+}
4072+
4073+if (exit === 1) {
4074+ console.log(item);
4075+}
4076+
4077+function decodeUser(json) {
4078+ if (typeof json === "object" && json !== null && !Array.isArray(json)) {
4079+ let match = json["name"];
4080+ let match$1 = json["age"];
4081+ if (typeof match === "string" && typeof match$1 === "number") {
4082+ return [match, match$1 | 0];
4083+ }
4084+ throw {
4085+ RE_EXN_ID: "Assert_failure",
4086+ _1: ["_tempFile.res", 26, 11],
4087+ Error: new Error(),
4088+ };
4089+ }
4090+ throw {
4091+ RE_EXN_ID: "Assert_failure",
4092+ _1: ["_tempFile.res", 28, 9],
4093+ Error: new Error(),
4094+ };
4095+}
4096+
4097+try {
4098+ console.log(decodeUser({}));
4099+} catch (raw_loc) {
4100+ let loc = Primitive_exceptions.internalToException(raw_loc);
4101+ if (loc.RE_EXN_ID === "Assert_failure") {
4102+ console.log(loc._1);
4103+ } else {
4104+ throw loc;
4105+ }
4106+}
4107+
4108+export { getItem, result, decodeUser };
4109+```
4110+
4111+</CodeTab>
4112+
4113+### `Failure`
4114+
4115+Exception thrown to signal that the given arguments do not make sense. This
4116+exception takes a string as an argument.
4117+
4118+<CodeTab labels={["ReScript", "JS Output"]}>
4119+```res
4120+let isValidEmail = email => {
4121+ let hasAtSign = String.includes(email, "@")
4122+ let hasDot = String.includes(email, ".")
4123+ if !(hasAtSign && hasDot) {
4124+ throw(Failure("Invalid email address"))
4125+ } else {
4126+ true
4127+ }
4128+}
4129+
4130+let isValid = try isValidEmail("rescript.org") catch {
4131+| Failure(msg) => {
4132+Console.error(msg)
4133+false
4134+}
4135+}
4136+
4137+````
4138+
4139+```js
4140+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
4141+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4142+
4143+function getItem(item) {
4144+ if (item === 3) {
4145+ return 1;
4146+ }
4147+ throw {
4148+ RE_EXN_ID: "Not_found",
4149+ Error: new Error()
4150+ };
4151+}
4152+
4153+let result;
4154+
4155+try {
4156+ result = getItem(2);
4157+} catch (raw_exn) {
4158+ let exn = Primitive_exceptions.internalToException(raw_exn);
4159+ if (exn.RE_EXN_ID === "Not_found") {
4160+ result = 0;
4161+ } else {
4162+ throw exn;
4163+ }
4164+}
4165+
4166+let exit = 0;
4167+
4168+let item;
4169+
4170+try {
4171+ item = Stdlib_List.getOrThrow({
4172+ hd: 1,
4173+ tl: {
4174+ hd: 2,
4175+ tl: {
4176+ hd: 3,
4177+ tl: /* [] */0
4178+ }
4179+ }
4180+ }, 4);
4181+ exit = 1;
4182+} catch (raw_exn$1) {
4183+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
4184+ if (exn$1.RE_EXN_ID === "Not_found") {
4185+ console.log("No such item found!");
4186+ } else {
4187+ throw exn$1;
4188+ }
4189+}
4190+
4191+if (exit === 1) {
4192+ console.log(item);
4193+}
4194+
4195+function isValidEmail(email) {
4196+ let hasAtSign = email.includes("@");
4197+ let hasDot = email.includes(".");
4198+ if (hasAtSign && hasDot) {
4199+ return true;
4200+ }
4201+ throw {
4202+ RE_EXN_ID: "Failure",
4203+ _1: "Invalid email address",
4204+ Error: new Error()
4205+ };
4206+}
4207+
4208+let isValid;
4209+
4210+try {
4211+ isValid = isValidEmail("rescript.org");
4212+} catch (raw_msg) {
4213+ let msg = Primitive_exceptions.internalToException(raw_msg);
4214+ if (msg.RE_EXN_ID === "Failure") {
4215+ console.error(msg._1);
4216+ isValid = false;
4217+ } else {
4218+ throw msg;
4219+ }
4220+}
4221+
4222+export {
4223+ getItem,
4224+ result,
4225+ isValidEmail,
4226+ isValid,
4227+}
4228+````
4229+
4230+</CodeTab>
4231+
4232+### `Division_by_zero`
4233+
4234+Exception thrown by integer division and remainder operations when their second argument is zero.
4235+
4236+<CodeTab labels={["ReScript", "JS Output"]}>
4237+```res
4238+// ReScript throws `Division_by_zero` if the denominator is zero
4239+let result = try Some(10 / 0) catch {
4240+| Division_by_zero => None
4241+}
4242+
4243+Console.log(result) // None
4244+
4245+````
4246+
4247+```js
4248+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
4249+import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
4250+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4251+
4252+function getItem(item) {
4253+ if (item === 3) {
4254+ return 1;
4255+ }
4256+ throw {
4257+ RE_EXN_ID: "Not_found",
4258+ Error: new Error()
4259+ };
4260+}
4261+
4262+try {
4263+ getItem(2);
4264+} catch (raw_exn) {
4265+ let exn = Primitive_exceptions.internalToException(raw_exn);
4266+ if (exn.RE_EXN_ID !== "Not_found") {
4267+ throw exn;
4268+ }
4269+}
4270+
4271+let exit = 0;
4272+
4273+let item;
4274+
4275+try {
4276+ item = Stdlib_List.getOrThrow({
4277+ hd: 1,
4278+ tl: {
4279+ hd: 2,
4280+ tl: {
4281+ hd: 3,
4282+ tl: /* [] */0
4283+ }
4284+ }
4285+ }, 4);
4286+ exit = 1;
4287+} catch (raw_exn$1) {
4288+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
4289+ if (exn$1.RE_EXN_ID === "Not_found") {
4290+ console.log("No such item found!");
4291+ } else {
4292+ throw exn$1;
4293+ }
4294+}
4295+
4296+if (exit === 1) {
4297+ console.log(item);
4298+}
4299+
4300+let result;
4301+
4302+try {
4303+ result = Primitive_int.div(10, 0);
4304+} catch (raw_exn$2) {
4305+ let exn$2 = Primitive_exceptions.internalToException(raw_exn$2);
4306+ if (exn$2.RE_EXN_ID === "Division_by_zero") {
4307+ result = undefined;
4308+ } else {
4309+ throw exn$2;
4310+ }
4311+}
4312+
4313+console.log(result);
4314+
4315+export {
4316+ getItem,
4317+ result,
4318+}
4319+````
4320+
4321+</CodeTab>
4322+
4323+## Catching JS Exceptions
4324+
4325+To distinguish between JavaScript exceptions and ReScript exceptions, ReScript namespaces JS exceptions under the `JsExn(payload)` variant. To catch an exception thrown from the JS side:
4326+
4327+Throw an exception from JS:
4328+
4329+```js
4330+// Example.js
4331+
4332+exports.someJsFunctionThatThrows = () => {
4333+ throw new Error("A Glitch in the Matrix!");
4334+};
4335+```
4336+
4337+Then catch it from ReScript:
4338+
4339+```res nocheck
4340+// import the method in Example.js
4341+@module("./Example")
4342+external someJsFunctionThatThrows: () => unit = "someJsFunctionThatThrows"
4343+
4344+try {
4345+ // call the external method
4346+ someJSFunctionThatThrows()
4347+} catch {
4348+| JsExn(exn) =>
4349+ switch JsExn.message(exn) {
4350+ | Some(m) => Console.log("Caught a JS exception! Message: " ++ m)
4351+ | None => ()
4352+ }
4353+}
4354+```
4355+
4356+The payload `exn` here is of type `unknown` since in JS you can throw anything. To operate on `exn`, do like the code above by using the standard library's [`JsExn`](/docs/manual/api/stdlib/jsexn) module's helpers
4357+or use [`Type.Classify.classify`](/docs/manual/api/stdlib/type/classify#value-classify) to get more information about the runtime type of `exn`.
4358+
4359+## Throw a JS Exception
4360+
4361+### Throw a JS Error
4362+
4363+`throw(MyException)` throws a ReScript exception. To throw a JavaScript error (whatever your purpose is), use `JsError.throwWithMessage`:
4364+
4365+<CodeTab labels={["ReScript", "JS Output"]}>
4366+
4367+```res
4368+let myTest = () => {
4369+ JsError.throwWithMessage("Hello!")
4370+}
4371+```
4372+
4373+```js
4374+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
4375+import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
4376+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4377+
4378+function getItem(item) {
4379+ if (item === 3) {
4380+ return 1;
4381+ }
4382+ throw {
4383+ RE_EXN_ID: "Not_found",
4384+ Error: new Error(),
4385+ };
4386+}
4387+
4388+let result;
4389+
4390+try {
4391+ result = getItem(2);
4392+} catch (raw_exn) {
4393+ let exn = Primitive_exceptions.internalToException(raw_exn);
4394+ if (exn.RE_EXN_ID === "Not_found") {
4395+ result = 0;
4396+ } else {
4397+ throw exn;
4398+ }
4399+}
4400+
4401+let exit = 0;
4402+
4403+let item;
4404+
4405+try {
4406+ item = Stdlib_List.getOrThrow(
4407+ {
4408+ hd: 1,
4409+ tl: {
4410+ hd: 2,
4411+ tl: {
4412+ hd: 3,
4413+ tl: /* [] */ 0,
4414+ },
4415+ },
4416+ },
4417+ 4,
4418+ );
4419+ exit = 1;
4420+} catch (raw_exn$1) {
4421+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
4422+ if (exn$1.RE_EXN_ID === "Not_found") {
4423+ console.log("No such item found!");
4424+ } else {
4425+ throw exn$1;
4426+ }
4427+}
4428+
4429+if (exit === 1) {
4430+ console.log(item);
4431+}
4432+
4433+function myTest() {
4434+ return Stdlib_JsError.throwWithMessage("Hello!");
4435+}
4436+
4437+export { getItem, result, myTest };
4438+```
4439+
4440+</CodeTab>
4441+
4442+Then you can catch it from the JS side:
4443+
4444+```js
4445+// after importing `myTest`...
4446+try {
4447+ myTest();
4448+} catch (e) {
4449+ console.log(e.message); // "Hello!"
4450+}
4451+```
4452+
4453+### Throw a value that is not an JS Error
4454+
4455+If you want to throw any value that is not a valid JS Error, use `JsExn.throw`:
4456+
4457+<CodeTab labels={["ReScript", "JS Output"]}>
4458+
4459+```res
4460+let myTest = () => {
4461+ JsExn.throw("some non-error value!")
4462+}
4463+```
4464+
4465+```js
4466+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
4467+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4468+
4469+function getItem(item) {
4470+ if (item === 3) {
4471+ return 1;
4472+ }
4473+ throw {
4474+ RE_EXN_ID: "Not_found",
4475+ Error: new Error(),
4476+ };
4477+}
4478+
4479+let result;
4480+
4481+try {
4482+ result = getItem(2);
4483+} catch (raw_exn) {
4484+ let exn = Primitive_exceptions.internalToException(raw_exn);
4485+ if (exn.RE_EXN_ID === "Not_found") {
4486+ result = 0;
4487+ } else {
4488+ throw exn;
4489+ }
4490+}
4491+
4492+let exit = 0;
4493+
4494+let item;
4495+
4496+try {
4497+ item = Stdlib_List.getOrThrow(
4498+ {
4499+ hd: 1,
4500+ tl: {
4501+ hd: 2,
4502+ tl: {
4503+ hd: 3,
4504+ tl: /* [] */ 0,
4505+ },
4506+ },
4507+ },
4508+ 4,
4509+ );
4510+ exit = 1;
4511+} catch (raw_exn$1) {
4512+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
4513+ if (exn$1.RE_EXN_ID === "Not_found") {
4514+ console.log("No such item found!");
4515+ } else {
4516+ throw exn$1;
4517+ }
4518+}
4519+
4520+if (exit === 1) {
4521+ console.log(item);
4522+}
4523+
4524+function myTest() {
4525+ throw "some non-error value!";
4526+}
4527+
4528+export { getItem, result, myTest };
4529+```
4530+
4531+</CodeTab>
4532+
4533+Then you can catch it from the JS side:
4534+
4535+```js
4536+// after importing `myTest`...
4537+try {
4538+ myTest();
4539+} catch (message) {
4540+ console.log(message); // "Hello!"
4541+}
4542+```
4543+
4544+## Catch ReScript Exceptions from JS
4545+
4546+To let JavaScript code work with exception-throwing ReScript code, you don't need to throw a JS exception. ReScript exceptions can be used directly from JavaScript.
4547+
4548+<CodeTab labels={["ReScript", "JS Output"]}>
4549+
4550+```res
4551+exception BadArgument({myMessage: string})
4552+
4553+let myTest = () => {
4554+ throw(BadArgument({myMessage: "Oops!"}))
4555+}
4556+```
4557+
4558+```js
4559+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
4560+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4561+
4562+function getItem(item) {
4563+ if (item === 3) {
4564+ return 1;
4565+ }
4566+ throw {
4567+ RE_EXN_ID: "Not_found",
4568+ Error: new Error(),
4569+ };
4570+}
4571+
4572+let result;
4573+
4574+try {
4575+ result = getItem(2);
4576+} catch (raw_exn) {
4577+ let exn = Primitive_exceptions.internalToException(raw_exn);
4578+ if (exn.RE_EXN_ID === "Not_found") {
4579+ result = 0;
4580+ } else {
4581+ throw exn;
4582+ }
4583+}
4584+
4585+let exit = 0;
4586+
4587+let item;
4588+
4589+try {
4590+ item = Stdlib_List.getOrThrow(
4591+ {
4592+ hd: 1,
4593+ tl: {
4594+ hd: 2,
4595+ tl: {
4596+ hd: 3,
4597+ tl: /* [] */ 0,
4598+ },
4599+ },
4600+ },
4601+ 4,
4602+ );
4603+ exit = 1;
4604+} catch (raw_exn$1) {
4605+ let exn$1 = Primitive_exceptions.internalToException(raw_exn$1);
4606+ if (exn$1.RE_EXN_ID === "Not_found") {
4607+ console.log("No such item found!");
4608+ } else {
4609+ throw exn$1;
4610+ }
4611+}
4612+
4613+if (exit === 1) {
4614+ console.log(item);
4615+}
4616+
4617+let BadArgument = /* @__PURE__ */ Primitive_exceptions.create(
4618+ "_tempFile.BadArgument",
4619+);
4620+
4621+function myTest() {
4622+ throw {
4623+ RE_EXN_ID: BadArgument,
4624+ myMessage: "Oops!",
4625+ Error: new Error(),
4626+ };
4627+}
4628+
4629+export { getItem, result, BadArgument, myTest };
4630+```
4631+
4632+</CodeTab>
4633+
4634+Then, in your JS:
4635+
4636+```js
4637+// after importing `myTest`...
4638+try {
4639+ myTest();
4640+} catch (e) {
4641+ console.log(e.myMessage); // "Oops!"
4642+ console.log(e.Error.stack); // the stack trace
4643+}
4644+```
4645+
4646+The above `BadArgument` exception takes an inline record type. We special-case compile the exception as `{RE_EXN_ID, myMessage, Error}` for good ergonomics. If the exception instead took ordinary positional arguments, l like the standard library's `Invalid_argument("Oops!")`, which takes a single argument, the argument is compiled to JS as the field `_1` instead. A second positional argument would compile to `_2`, etc.
4647+
4648+## Tips & Tricks
4649+
4650+When you have ordinary variants, you often don't **need** exceptions. For example, instead of throwing when `item` can't be found in a collection, try to return an `option<item>` (`None` in this case) instead.
4651+
4652+### Catch Both ReScript and JS Exceptions in the Same `catch` Clause
4653+
4654+```res nocheck
4655+try {
4656+ someOtherJSFunctionThatThrows()
4657+} catch {
4658+| Not_found => ... // catch a ReScript exception
4659+| Invalid_argument(_) => ... // catch a second ReScript exception
4660+| JsExn(exn) => ... // catch the JS exception
4661+}
4662+```
4663+
4664+This technically works, but hopefully you don't ever have to work with such code...
4665+
4666+---
4667+title: "Extensible Variant"
4668+description: "Extensible Variants in ReScript"
4669+canonical: "/docs/manual/extensible-variant"
4670+section: "Advanced Features"
4671+order: 1
4672+---
4673+
4674+# Extensible Variant
4675+
4676+Variant types are usually constrained to a fixed set of constructors. There may be very rare cases where you still want to be able to add constructors to a variant type even after its initial type declaration. For this, we offer extensible variant types.
4677+
4678+## Definition and Usage
4679+
4680+<CodeTab labels={["ReScript", "JS Output"]}>
4681+
4682+```res
4683+type t = ..
4684+
4685+type t += Other
4686+
4687+type t +=
4688+ | Point(float, float)
4689+ | Line(float, float, float, float)
4690+```
4691+
4692+```js
4693+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
4694+
4695+let Other = /* @__PURE__ */ Primitive_exceptions.create("_tempFile.Other");
4696+
4697+let Point = /* @__PURE__ */ Primitive_exceptions.create("_tempFile.Point");
4698+
4699+let Line = /* @__PURE__ */ Primitive_exceptions.create("_tempFile.Line");
4700+
4701+export { Other, Point, Line };
4702+```
4703+
4704+</CodeTab>
4705+
4706+The `..` in the type declaration above defines an extensible variant `type t`. The `+=` operator is then used to add constructors to the given type.
4707+
4708+**Note:** Don't forget the leading `type` keyword when using the `+=` operator!
4709+
4710+## Pattern Matching Caveats
4711+
4712+Extensible variants are open-ended, so the compiler will not be able to exhaustively pattern match all available cases. You will always need to provide a default `_` case for every `switch` expression.
4713+
4714+<CodeTab labels={["ReScript", "JS Output"]}>
4715+
4716+```res nocheck
4717+let print = v =>
4718+ switch v {
4719+ | Point(x, y) => Console.log2("Point", (x, y))
4720+ | Line(ax, ay, bx, by) => Console.log2("Line", (ax, ay, bx, by))
4721+ | Other
4722+ | _ => Console.log("Other")
4723+ }
4724+```
4725+
4726+```js
4727+function print(v) {
4728+ if (v.RE_EXN_ID === Point) {
4729+ console.log("Point", [v._1, v._2]);
4730+ } else if (v.RE_EXN_ID === Line) {
4731+ console.log("Line", [v._1, v._2, v._3, v._4]);
4732+ } else {
4733+ console.log("Other");
4734+ }
4735+}
4736+```
4737+
4738+</CodeTab>
4739+
4740+## Tips & Tricks
4741+
4742+**Fun fact:** Like [exception](./exception.mdx), extensible variant It's one of the very few use-case where extensible variants make sense.
4743+
4744+We usually recommend sticking with common [variants](./variant.mdx) as much as possible to reap the benefits of exhaustive pattern matching.
4745+
4746+---
4747+title: "External (Bind to Any JS Library)"
4748+description: "The external keyword"
4749+canonical: "/docs/manual/external"
4750+section: "JavaScript Interop"
4751+order: 3
4752+---
4753+
4754+# External (Bind to Any JS Library)
4755+
4756+`external` is the primary ReScript feature for bringing in and using JavaScript values.
4757+
4758+`external` is like a let binding, but:
4759+
4760+- The right side of `=` isn't a value; it's the name of the JS value you're referring to.
4761+- The type for the binding is mandatory, since we need to know what the type of that JS value is.
4762+- Can only exist at the top level of a file or module.
4763+
4764+<CodeTab labels={["ReScript", "JS Output"]}>
4765+
4766+```res
4767+@val external setTimeout: (unit => unit, int) => float = "setTimeout"
4768+```
4769+
4770+```js
4771+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
4772+```
4773+
4774+</CodeTab>
4775+
4776+There are several kinds of `external`s, differentiated and/or augmented through the [attribute](./attribute.mdx) they carry. This page deals with the general, shared mechanism behind most `external`s. The different `external`s are documented in their respective pages later. A few notable ones:
4777+
4778+- `@val`, `@scope`: [bind to global JS values](./bind-to-global-js-values.mdx).
4779+- `@module`: [bind to JS imported/exported values](./import-from-export-to-js.mdx).
4780+- `@send`: [bind to JS methods](./bind-to-js-function.mdx).
4781+
4782+You can also use our [Syntax Lookup](../../syntax-lookup/) tool to find them.
4783+
4784+Related: See our [interop cheatsheet](./interop-cheatsheet.mdx) for an overview.
4785+
4786+## Usage
4787+
4788+Once declared, you can use an `external` as a normal value, just like a let binding.
4789+
4790+## Tips & Tricks
4791+
4792+`external` + ReScript objects are a wonderful combination for quick prototyping. Check the JS output tab:
4793+
4794+<CodeTab labels={["ReScript", "JS Output"]}>
4795+
4796+```res
4797+// The type of document is just some random type 'a
4798+// that we won't bother to specify
4799+@val external document: 'a = "document"
4800+
4801+// call a method
4802+document["addEventListener"]("mouseup", _event => {
4803+ Console.log("clicked!")
4804+})
4805+
4806+// get a property
4807+let loc = document["location"]
4808+
4809+// set a property
4810+document["location"]["href"] = "rescript-lang.org"
4811+```
4812+
4813+```js
4814+document.addEventListener("mouseup", (_event) => {
4815+ console.log("clicked!");
4816+});
4817+
4818+let loc = document.location;
4819+
4820+document.location.href = "rescript-lang.org";
4821+
4822+export { loc };
4823+```
4824+
4825+</CodeTab>
4826+
4827+We've specified `document`'s type as `'a`, a placeholder type that's polymorphic. Any value can be passed there, so you're not getting much type safety (except the inferences at various call sites). This is useful for quickly getting started with a JavaScript library in ReScript since you can write bindings directly for any API you need.
4828+
4829+For more rigidly typed bindings, see the other interop pages in this section.
4830+
4831+## Performance & Output Readability
4832+
4833+`external`s declarations are inlined into their callers during compilation, **and completely disappear from the JS output**. This means any time you use one, you can be sure that you're not incurring extra JavaScript \<-> ReScript conversion cost.
4834+
4835+Additionally, no extra ReScript-specific runtime is better for output readability.
4836+
4837+> **Note:** do also use `external`s and the `@blabla` attributes in the interface files. Otherwise the inlining won't happen.
4838+
4839+## Design Decisions
4840+
4841+ReScript takes interoperating with existing code very seriously. Our type system has very strong guarantees. However, such strong feature also means that, without a great interop system, it'd be very hard to gradually convert a codebase over to ReScript. Fortunately, our interop are comprehensive and cooperate very well with most existing JavaScript code.
4842+
4843+The combination of a sound type system + great interop means that we get the benefits of a traditional gradual type system regarding incremental codebase coverage & conversion, without the downside of such gradual type system: complex features to support existing patterns, slow analysis, diminishing return in terms of type coverage, etc.
4844+
4845+---
4846+title: "Function"
4847+description: "Function syntax in ReScript"
4848+canonical: "/docs/manual/function"
4849+section: "Language Features"
4850+order: 13
4851+---
4852+
4853+# Function
4854+
4855+_Cheat sheet for the full function syntax at the end_.
4856+
4857+ReScript functions are declared with an arrow and return an expression. They compile to clean JavaScript functions.
4858+
4859+<CodeTab labels={["ReScript", "JS Output"]}>
4860+
4861+```res prelude
4862+let greet = (name) => "Hello " ++ name
4863+```
4864+
4865+```js
4866+function greet(name) {
4867+ return "Hello " + name;
4868+}
4869+```
4870+
4871+</CodeTab>
4872+
4873+This declares a function and assigns to it the name `greet`.
4874+
4875+When ReScript can evaluate a known pure function call ahead of time, it can emit the resulting data directly:
4876+
4877+<CodeTab labels={["ReScript", "JS Output"]}>
4878+
4879+```res nocheck
4880+let message = greet("world!") // "Hello world!"
4881+```
4882+
4883+```js
4884+function greet(name) {
4885+ return "Hello " + name;
4886+}
4887+
4888+let message = "Hello world!";
4889+
4890+export { greet, message };
4891+```
4892+
4893+</CodeTab>
4894+
4895+Multi-arguments functions have arguments separated by comma:
4896+
4897+If all the arguments are known up front, ReScript can precompute the result too:
4898+
4899+<CodeTab labels={["ReScript", "JS Output"]}>
4900+
4901+```res nocheck
4902+let add = (x, y, z) => x + y + z
4903+let sum = add(1, 2, 3) // 6
4904+```
4905+
4906+```js
4907+function greet(name) {
4908+ return "Hello " + name;
4909+}
4910+
4911+function add(x, y, z) {
4912+ return (((x + y) | 0) + z) | 0;
4913+}
4914+
4915+let sum = 6;
4916+
4917+export { greet, add, sum };
4918+```
4919+
4920+</CodeTab>
4921+
4922+For longer functions, you'd surround the body with a block:
4923+
4924+<CodeTab labels={["ReScript", "JS Output"]}>
4925+
4926+```res nocheck
4927+let greetMore = (name) => {
4928+ let part1 = "Hello"
4929+ part1 ++ " " ++ name
4930+}
4931+```
4932+
4933+```js
4934+function greet(name) {
4935+ return "Hello " + name;
4936+}
4937+
4938+function greetMore(name) {
4939+ return "Hello " + name;
4940+}
4941+
4942+export { greet, greetMore };
4943+```
4944+
4945+</CodeTab>
4946+
4947+If your function has no argument, just write `let greetMore = () => {...}`.
4948+
4949+## Labeled Arguments
4950+
4951+Multi-arguments functions, especially those whose arguments are of the same type, can be confusing to call.
4952+
4953+<CodeTab labels={["ReScript", "JS Output"]}>
4954+
4955+```res nocheck
4956+let addCoordinates = (x, y) => {
4957+ // use x and y here
4958+}
4959+// ...
4960+addCoordinates(5, 6) // which is x, which is y?
4961+```
4962+
4963+```js
4964+function addCoordinates(x, y) {
4965+ // use x and y here
4966+}
4967+
4968+addCoordinates(5, 6);
4969+```
4970+
4971+</CodeTab>
4972+
4973+You can attach labels to an argument by prefixing the name with the `~` symbol:
4974+
4975+<CodeTab labels={["ReScript", "JS Output"]}>
4976+
4977+```res nocheck
4978+let addCoordinates = (~x, ~y) => {
4979+ // use x and y here
4980+}
4981+// ...
4982+addCoordinates(~x=5, ~y=6)
4983+```
4984+
4985+```js
4986+function addCoordinates(x, y) {
4987+ // use x and y here
4988+}
4989+
4990+addCoordinates(5, 6);
4991+```
4992+
4993+</CodeTab>
4994+
4995+You can provide the arguments in **any order**:
4996+
4997+<CodeTab labels={["ReScript", "JS Output"]}>
4998+
4999+```res nocheck
5000+addCoordinates(~y=6, ~x=5)
5001+```
5002+
5003+```js
5004+addCoordinates(5, 6);
5005+```
5006+
5007+</CodeTab>
5008+
5009+The `~x` part in the declaration means the function accepts an argument labeled `x` and can refer to it in the function body by the same name. You can also refer to the arguments inside the function body by a different name for conciseness:
5010+
5011+<CodeTab labels={["ReScript", "JS Output"]}>
5012+
5013+```res nocheck
5014+let drawCircle = (~radius as r, ~color as c) => {
5015+ setColor(c)
5016+ startAt(r, r)
5017+ // ...
5018+}
5019+
5020+drawCircle(~radius=10, ~color="red")
5021+```
5022+
5023+```js
5024+function drawCircle(r, c) {
5025+ setColor(c);
5026+ return startAt(r, r);
5027+}
5028+
5029+drawCircle(10, "red");
5030+```
5031+
5032+</CodeTab>
5033+
5034+As a matter of fact, `(~radius)` is just a shorthand for `(~radius as radius)`.
5035+
5036+Here's the syntax for typing the arguments:
5037+
5038+<CodeTab labels={["ReScript", "JS Output"]}>
5039+
5040+```res nocheck
5041+let drawCircle = (~radius as r: int, ~color as c: string) => {
5042+ // code here
5043+}
5044+```
5045+
5046+```js
5047+function drawCircle(r, c) {
5048+ // code here
5049+}
5050+```
5051+
5052+</CodeTab>
5053+
5054+## Optional Labeled Arguments
5055+
5056+Labeled function arguments can be made optional during declaration. You can then omit them when calling the function.
5057+
5058+<CodeTab labels={["ReScript", "JS Output"]}>
5059+
5060+```res nocheck
5061+// radius can be omitted
5062+let drawCircle = (~color, ~radius=?) => {
5063+ setColor(color)
5064+ switch radius {
5065+ | None => startAt(1, 1)
5066+ | Some(r_) => startAt(r_, r_)
5067+ }
5068+}
5069+```
5070+
5071+```js
5072+var Caml_option = require("./stdlib/caml_option.js");
5073+
5074+function drawCircle(color, radius) {
5075+ setColor(color);
5076+ if (radius === undefined) {
5077+ return startAt(1, 1);
5078+ }
5079+ var r_ = Caml_option.valFromOption(radius);
5080+ return startAt(r_, r_);
5081+}
5082+```
5083+
5084+</CodeTab>
5085+
5086+When given in this syntax, `radius` is **wrapped** in the standard library's `option` type, defaulting to `None`. If provided, it'll be wrapped with a `Some`. So `radius`'s type value is `None | Some(int)` here.
5087+
5088+Unlike [nullable](./null-undefined-option.mdx), optional fields don't
5089+
5090+### Signatures and Type Annotations
5091+
5092+Functions with optional labeled arguments can be confusing when it comes to signature and type annotations. Indeed, the type of an optional labeled argument looks different depending on whether you're calling the function, or working inside the function body. Outside the function, a raw value is either passed in (`int`, for example), or left off entirely. Inside the function, the parameter is always there, but its value is an option (`option<int>`). This means that the type signature is different, depending on whether you're writing out the function type, or the parameter type annotation. The first being a raw value, and the second being an option.
5093+
5094+If we get back to our previous example and both add a signature and type annotations to its argument, we get this:
5095+
5096+<CodeTab labels={["ReScript", "JS Output"]}>
5097+
5098+```res nocheck
5099+let drawCircle: (~color: color, ~radius: int=?) => unit =
5100+ (~color: color, ~radius: option<int>=?) => {
5101+ setColor(color)
5102+ switch radius {
5103+ | None => startAt(1, 1)
5104+ | Some(r_) => startAt(r_, r_)
5105+ }
5106+ }
5107+```
5108+
5109+```js
5110+function drawCircle(color, radius) {
5111+ setColor(color);
5112+ if (radius !== undefined) {
5113+ return startAt(radius, radius);
5114+ } else {
5115+ return startAt(1, 1);
5116+ }
5117+}
5118+```
5119+
5120+</CodeTab>
5121+
5122+The first line is the function's signature, we would define it like that in an interface file (see [Signatures](./module.mdx#signatures)). The function's signature describes the types that the **outside world** interacts with, hence the type `int` for `radius` because it indeed expects an `int` when called.
5123+
5124+In the second line, we annotate the arguments to help us remember the types of the arguments when we use them **inside** the function's body, here indeed `radius` will be an `option<int>` inside the function.
5125+
5126+So if you happen to struggle when writing the signature of a function with optional labeled arguments, try to remember this!
5127+
5128+### Explicitly Passed Optional
5129+
5130+Sometimes, you might want to forward a value to a function without knowing whether the value is `None` or `Some(a)`. Naively, you'd do:
5131+
5132+<CodeTab labels={["ReScript", "JS Output"]}>
5133+
5134+```res nocheck
5135+let result =
5136+ switch payloadRadius {
5137+ | None => drawCircle(~color)
5138+ | Some(r) => drawCircle(~color, ~radius=r)
5139+ }
5140+```
5141+
5142+```js
5143+var r = payloadRadius;
5144+
5145+var result =
5146+ r !== undefined
5147+ ? drawCircle(color, Caml_option.valFromOption(r))
5148+ : drawCircle(color);
5149+```
5150+
5151+</CodeTab>
5152+
5153+This quickly gets tedious. We provide a shortcut:
5154+
5155+<CodeTab labels={["ReScript", "JS Output"]}>
5156+
5157+```res nocheck
5158+let result = drawCircle(~color, ~radius=?payloadRadius)
5159+```
5160+
5161+```js
5162+var result = drawCircle(1, undefined);
5163+```
5164+
5165+</CodeTab>
5166+
5167+This means "I understand `radius` is optional, and that when I pass it a value it needs to be an `int`, but I don't know whether the value I'm passing is `None` or `Some(val)`, so I'll pass you the whole `option` wrapper".
5168+
5169+### Optional with Default Value
5170+
5171+Optional labeled arguments can also be provided a default value. In this case, they aren't wrapped in an `option` type.
5172+
5173+<CodeTab labels={["ReScript", "JS Output"]}>
5174+
5175+```res nocheck
5176+let drawCircle = (~radius=1, ~color) => {
5177+ setColor(color)
5178+ startAt(radius, radius)
5179+}
5180+```
5181+
5182+```js
5183+function drawCircle(radiusOpt, color) {
5184+ var radius = radiusOpt !== undefined ? radiusOpt : 1;
5185+ setColor(color);
5186+ return startAt(radius, radius);
5187+}
5188+```
5189+
5190+</CodeTab>
5191+
5192+## Recursive Functions
5193+
5194+ReScript chooses the sane default of preventing a function to be called recursively within itself. To make a function recursive, add the `rec` keyword after the `let`:
5195+
5196+<CodeTab labels={["ReScript", "JS Output"]}>
5197+
5198+```res nocheck
5199+let rec neverTerminate = () => neverTerminate()
5200+```
5201+
5202+```js
5203+function greet(name) {
5204+ return "Hello " + name;
5205+}
5206+
5207+function neverTerminate() {
5208+ while (true) {
5209+ continue;
5210+ }
5211+}
5212+
5213+export { greet, neverTerminate };
5214+```
5215+
5216+</CodeTab>
5217+
5218+A simple recursive function may look like this:
5219+
5220+<CodeTab labels={["ReScript", "JS Output"]}>
5221+
5222+```res nocheck
5223+// Recursively check every item on the list until one equals the `item`
5224+// argument. If a match is found, return `true`, otherwise return `false`
5225+let rec listHas = (list, item) =>
5226+ switch list {
5227+ | list{} => false
5228+ | list{a, ...rest} => a === item || listHas(rest, item)
5229+ }
5230+```
5231+
5232+```js
5233+function greet(name) {
5234+ return "Hello " + name;
5235+}
5236+
5237+function listHas(_list, item) {
5238+ while (true) {
5239+ let list = _list;
5240+ if (list === 0) {
5241+ return false;
5242+ }
5243+ if (list.hd === item) {
5244+ return true;
5245+ }
5246+ _list = list.tl;
5247+ continue;
5248+ }
5249+}
5250+
5251+export { greet, listHas };
5252+```
5253+
5254+</CodeTab>
5255+
5256+Recursively calling a function is bad for performance and the call stack. However, ReScript intelligently compiles [tail recursion](https://stackoverflow.com/questions/33923/what-is-tail-recursion) into a fast JavaScript loop. Try checking the JS output of the above code!
5257+
5258+### Mutually Recursive Functions
5259+
5260+Mutually recursive functions start like a single recursive function using the
5261+`rec` keyword, and then are chained together with `and`:
5262+
5263+<CodeTab labels={["ReScript", "JS Output"]}>
5264+
5265+```res nocheck
5266+let rec callSecond = () => callFirst()
5267+and callFirst = () => callSecond()
5268+```
5269+
5270+```js
5271+function greet(name) {
5272+ return "Hello " + name;
5273+}
5274+
5275+function callSecond() {
5276+ while (true) {
5277+ continue;
5278+ }
5279+}
5280+
5281+function callFirst() {
5282+ while (true) {
5283+ continue;
5284+ }
5285+}
5286+
5287+export { greet, callSecond, callFirst };
5288+```
5289+
5290+</CodeTab>
5291+
5292+## Partial Application
5293+
5294+**Since 11.0**
5295+
5296+To partially apply a function, use the explicit `...` syntax.
5297+
5298+<CodeTab labels={["ReScript", "JS Output"]}>
5299+```res nocheck
5300+let add = (a, b) => a + b
5301+let addFive = add(5, ...)
5302+```
5303+
5304+```js
5305+function add(a, b) {
5306+ return (a + b) | 0;
5307+}
5308+
5309+function addFive(extra) {
5310+ return (5 + extra) | 0;
5311+}
5312+```
5313+
5314+</CodeTab>
5315+
5316+## Async/Await
5317+
5318+Just as in JS, an async function can be declared by adding `async` before the definition, and `await` can be used in the body of such functions.
5319+The output looks like idiomatic JS:
5320+
5321+<CodeTab labels={["ReScript", "JS Output"]}>
5322+
5323+```res nocheck
5324+let getUserName = async (userId) => userId
5325+
5326+let greetUser = async (userId) => {
5327+ let name = await getUserName(userId)
5328+ "Hello " ++ name ++ "!"
5329+}
5330+```
5331+
5332+```js
5333+function greet(name) {
5334+ return "Hello " + name;
5335+}
5336+
5337+async function getUserName(userId) {
5338+ return userId;
5339+}
5340+
5341+async function greetUser(userId) {
5342+ let name = await getUserName(userId);
5343+ return "Hello " + name + "!";
5344+}
5345+
5346+export { greet, getUserName, greetUser };
5347+```
5348+
5349+</CodeTab>
5350+
5351+The return type of `getUser` is inferred to be `promise<string>`.
5352+Similarly, `await getUserName(userId)` returns a `string` when the function returns `promise<string>`.
5353+Using `await` outside of an `async` function (including in a non-async callback to an async function) is an error.
5354+
5355+### Ergonomic error handling
5356+
5357+Error handling is done by simply using `try`/`catch`, or a switch with an `exception` case, just as in functions that are not async.
5358+Both JS exceptions and exceptions defined in ReScript can be caught. The compiler takes care of packaging JS exceptions into the builtin `JsError` exception:
5359+
5360+<CodeTab labels={["ReScript", "JS Output"]}>
5361+
5362+```res nocheck
5363+exception SomeReScriptException
5364+
5365+let somethingThatMightThrow = async () => throw(SomeReScriptException)
5366+
5367+let someAsyncFn = async () => {
5368+ switch await somethingThatMightThrow() {
5369+ | data => Some(data)
5370+ | exception JsExn(_) => None
5371+ | exception SomeReScriptException => None
5372+ }
5373+}
5374+```
5375+
5376+```js
5377+import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
5378+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
5379+
5380+function greet(name) {
5381+ return "Hello " + name;
5382+}
5383+
5384+let SomeReScriptException = /* @__PURE__ */ Primitive_exceptions.create(
5385+ "_tempFile.SomeReScriptException",
5386+);
5387+
5388+async function somethingThatMightThrow() {
5389+ throw {
5390+ RE_EXN_ID: SomeReScriptException,
5391+ Error: new Error(),
5392+ };
5393+}
5394+
5395+async function someAsyncFn() {
5396+ let data;
5397+ try {
5398+ data = await somethingThatMightThrow();
5399+ } catch (raw_exn) {
5400+ let exn = Primitive_exceptions.internalToException(raw_exn);
5401+ if (exn.RE_EXN_ID === "JsExn") {
5402+ return;
5403+ }
5404+ if (exn.RE_EXN_ID === SomeReScriptException) {
5405+ return;
5406+ }
5407+ throw exn;
5408+ }
5409+ return Primitive_option.some(data);
5410+}
5411+
5412+export { greet, SomeReScriptException, somethingThatMightThrow, someAsyncFn };
5413+```
5414+
5415+</CodeTab>
5416+
5417+## The ignore() Function
5418+
5419+Occasionally you may want to ignore the return value of a function. ReScript provides an `ignore()` function that discards the value of its argument and returns `()`:
5420+
5421+<CodeTab labels={["ReScript", "JS Output"]}>
5422+
5423+```res nocheck
5424+mySideEffect()->Promise.catch(handleError)->ignore
5425+
5426+setTimeout(myFunc, 1000)->ignore
5427+```
5428+
5429+```js
5430+$$Promise.$$catch(mySideEffect(), function (prim) {
5431+ return handleError(prim);
5432+});
5433+
5434+setTimeout(function (prim) {
5435+ myFunc();
5436+}, 1000);
5437+```
5438+
5439+</CodeTab>
5440+
5441+## Tips & Tricks
5442+
5443+Cheat sheet for the function syntaxes:
5444+
5445+### Declaration
5446+
5447+```res nocheck
5448+// anonymous function
5449+(x, y) => 1
5450+// bind to a name
5451+let add = (x, y) => 1
5452+
5453+// labeled
5454+let add = (~first as x, ~second as y) => x + y
5455+// with punning sugar
5456+let add = (~first, ~second) => first + second
5457+
5458+// labeled with default value
5459+let add = (~first as x=1, ~second as y=2) => x + y
5460+// with punning
5461+let add = (~first=1, ~second=2) => first + second
5462+
5463+// optional
5464+let add = (~first as x=?, ~second as y=?) => switch x {...}
5465+// with punning
5466+let add = (~first=?, ~second=?) => switch first {...}
5467+```
5468+
5469+#### With Type Annotation
5470+
5471+```res nocheck
5472+// anonymous function
5473+(x: int, y: int): int => 1
5474+// bind to a name
5475+let add = (x: int, y: int): int => 1
5476+
5477+// labeled
5478+let add = (~first as x: int, ~second as y: int) : int => x + y
5479+// with punning sugar
5480+let add = (~first: int, ~second: int) : int => first + second
5481+
5482+// labeled with default value
5483+let add = (~first as x: int=1, ~second as y: int=2) : int => x + y
5484+// with punning sugar
5485+let add = (~first: int=1, ~second: int=2) : int => first + second
5486+
5487+// optional
5488+let add = (~first as x: option<int>=?, ~second as y: option<int>=?) : int => switch x {...}
5489+// with punning sugar
5490+// note that the caller would pass an `int`, not `option<int>`
5491+// Inside the function, `first` and `second` are `option<int>`.
5492+let add = (~first: option<int>=?, ~second: option<int>=?) : int => switch first {...}
5493+```
5494+
5495+### Application
5496+
5497+```res nocheck
5498+add(x, y)
5499+
5500+// labeled
5501+add(~first=1, ~second=2)
5502+// with punning sugar
5503+add(~first, ~second)
5504+
5505+// application with default value. Same as normal application
5506+add(~first=1, ~second=2)
5507+
5508+// explicit optional application
5509+add(~first=?Some(1), ~second=?Some(2))
5510+// with punning
5511+add(~first?, ~second?)
5512+```
5513+
5514+#### With Type Annotation
5515+
5516+```res nocheck
5517+// labeled
5518+add(~first=1: int, ~second=2: int)
5519+// with punning sugar
5520+add(~first: int, ~second: int)
5521+
5522+// application with default value. Same as normal application
5523+add(~first=1: int, ~second=2: int)
5524+
5525+// explicit optional application
5526+add(~first=?Some(1): option<int>, ~second=?Some(2): option<int>)
5527+// no punning sugar when you want to type annotate
5528+```
5529+
5530+### Standalone Type Signature
5531+
5532+```res nocheck
5533+// first arg type, second arg type, return type
5534+type add = (int, int) => int
5535+
5536+// labeled
5537+type add = (~first: int, ~second: int) => int
5538+
5539+// labeled
5540+type add = (~first: int=?, ~second: int=?, unit) => int
5541+```
5542+
5543+#### In Interface Files
5544+
5545+To annotate a function from the implementation file (`.res`) in your interface file (`.resi`):
5546+
5547+```res sig
5548+let add: (int, int) => int
5549+```
5550+
5551+The type annotation syntax is the same as described in [With Type Annotation](#with-type-annotation) above.
5552+
5553+**Don't** confuse `let add: myType` with `type add = myType`. When used in `.resi` interface files, the former exports the binding `add` while annotating it as type `myType`. The latter exports the type `add`, whose value is the type `myType`.
5554+
5555+---
5556+title: "Generalized Algebraic Data Types"
5557+description: "Generalized Algebraic Data Types in ReScript"
5558+canonical: "/docs/manual/generalized-algebraic-data-types"
5559+section: "Advanced Features"
5560+order: 4
5561+---
5562+
5563+# Generalized Algebraic Data Types
5564+
5565+Generalized Algebraic Data Types (GADTs) are an advanced feature of ReScript's type system. "Generalized" can be somewhat of a misnomer -- what they actually allow you to do is add some extra type-specificity to your variants. Using a GADT, you can give the individual cases of a variant _different_ types.
5566+
5567+For a quick overview of the use cases, reach for GADTs when:
5568+
5569+1. You need to distinguish between different members of a variant at the type level.
5570+2. You want to "hide" type information in a type-safe way, without resorting to casts.
5571+3. You need a function to return a different type depending on its input.
5572+
5573+GADTs usually are overkill, but when you need them, you need them! Understanding them from first principles is difficult, so it is best to explain through some motivating examples.
5574+
5575+## Distinguishing Constructors (Subtyping)
5576+
5577+Suppose a simple variant type that represents the current timezone of a date value. This handles both daylight savings and standard time:
5578+
5579+```res nocheck
5580+type timezone =
5581+ | EST // standard time
5582+ | EDT // daylight time
5583+ | CST // standard time
5584+ | CDT // daylight time
5585+// etc...
5586+```
5587+
5588+Using this variant type, we will end up having functions like this:
5589+
5590+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
5591+
5592+```res nocheck
5593+let convertToDaylight = tz => {
5594+ switch tz {
5595+ | EST => EDT
5596+ | CST => CDT
5597+ | EDT | CDT /* or, _ */ => failwith("Invalid timezone provided!")
5598+ }
5599+}
5600+```
5601+
5602+This function is only valid for a subset of our variant type's constructors but we can't handle this in a type-safe way using regular variants. We have to enforce that at runtime -- and moreover the compiler can't help us ensure we are failing only in the invalid cases. We are back to dynamically checking validity like we would in a language without static typing. If you work with a large variant type long enough, you will frequently find yourself writing repetitive catchall `switch` statements like the above, and for little actual benefit. The compiler should be able to help us here.
5603+
5604+Let's see if we can find a way for the compiler to help us with normal variants. We could define another variant type to distinguish the two kinds of timezone.
5605+
5606+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
5607+
5608+```res nocheck
5609+type daylightOrStandard =
5610+ | Daylight(timezone)
5611+ | Standard(timezone)
5612+```
5613+
5614+This has a lot of problems. For one, it's cumbersome and redundant. We would now have to pattern-match twice whenever we deal with a timezone that's wrapped up here. The compiler will force us to check whether we are dealing with daylight or standard time, but notice that there's nothing stopping us from providing invalid timezones to these constructors:
5615+
5616+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
5617+
5618+```res nocheck
5619+let invalidTz1 = Daylight(EST)
5620+let invalidTz2 = Standard(EDT)
5621+```
5622+
5623+Consequently, we still have to write our redundant catchall cases. We could define daylight savings time and standard time as two _separate_ types, and unify those in our `daylightOrStandard` variant.
5624+That could be a passable solution, but what we would really like to do is implement some kind of subtyping relationship.
5625+We have two _kinds_ of timezone. This is where GADTs are handy:
5626+
5627+```res nocheck
5628+type standard
5629+type daylight
5630+
5631+type rec timezone<_> =
5632+ | EST: timezone<standard>
5633+ | EDT: timezone<daylight>
5634+ | CST: timezone<standard>
5635+ | CDT: timezone<daylight>
5636+```
5637+
5638+We define our type with a type parameter. We manually annotate each constructor, providing it with the correct type parameter indicating whether it is standard or daylight. Each constructor is a `timezone`,
5639+but we've added another level of specificity using a type parameter. Constructors are now understood to be `standard` or `daylight` at the _type_ level. Now we can fix our function like this:
5640+
5641+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
5642+
5643+```res nocheck
5644+let convertToDaylight = tz => {
5645+ switch tz {
5646+ | EST => EDT
5647+ | CST => CDT
5648+ }
5649+}
5650+```
5651+
5652+The compiler can infer correctly that this function should only take `timezone<standard>` and only output
5653+`timezone<daylight>`. We don't need to add any redundant catchall cases and the compiler will even error if
5654+we try to return a standard timezone from this function. Actually, this seems like it could be a problem,
5655+we still want to be able to match on all cases of the variant sometimes, and a naive attempt at this will not pass the type checker. A naive example will fail:
5656+
5657+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
5658+
5659+```res nocheck
5660+let convertToDaylight = tz =>
5661+ switch tz {
5662+ | EST => EDT
5663+ | CST => CDT
5664+ | CDT => CDT
5665+ | EDT => EDT
5666+ }
5667+```
5668+
5669+This will complain that `daylight` and `standard` are incompatible. To fix this, we need to explicitly annotate to tell the compiler to accept both:
5670+
5671+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
5672+
5673+```res nocheck
5674+let convertToDaylight : type a. timezone<a> => timezone<daylight> = // ...
5675+```
5676+
5677+The syntax `type a.` here defines a _locally abstract type_ which basically tells the compiler that the type parameter a is some specific type, but we don't care what it is. The cost of the extra specificity and safety that
5678+GADTs give us is that the compiler less able to help us with type inference.
5679+
5680+## Varying return type
5681+
5682+Sometimes, a function should have a different return type based on what you give it, and GADTs are how we can do this in a type-safe way. We can implement a generic `add` function that works on both `int` or `float`:
5683+
5684+{/* this example purposefully has an error so it is not marked as an example */}
5685+
5686+```res nocheck
5687+type rec number<_> = Int(int): number<int> | Float(float): number<float>
5688+
5689+let add = (type a, x: number<a>, y: number<a>): a =>
5690+ switch (x, y) {
5691+ | (Int(x), Int(y)) => x + y
5692+ | (Float(x), Float(y)) => x + y
5693+ }
5694+
5695+let foo = add(Int(1), Int(2))
5696+
5697+let bar = add(Int(1), Float(2.0)) // the compiler will complain here
5698+```
5699+
5700+How does this work? The key thing is the function signature for add. The `number` GADT is acting as a _type witness_. We have told the compiler that the type parameter for `number` will be the same as the type we return -- both are set to `a`. So if we provide a `number<int>`, `a` equals `int`, and the function will therefore return an `int`.
5701+
5702+We can also use this to avoid returning `option` unnecessarily. We create an array searching function which either raises an exception, returns an `option`, or provides a `default` value depending on the behavior we ask for.[^2]
5703+
5704+[^2]: This example is adapted from [here](https://dev.realworldocaml.org/gadts.html).
5705+
5706+```res nocheck
5707+module IfNotFound = {
5708+ type rec t<_, _> =
5709+ | Raise: t<'a, 'a>
5710+ | ReturnNone: t<'a, option<'a>>
5711+ | DefaultTo('a): t<'a, 'a>
5712+}
5713+
5714+let flexible_find = (
5715+ type a b,
5716+ ~f: a => bool,
5717+ arr: array<a>,
5718+ ifNotFound: IfNotFound.t<a, b>,
5719+): b => {
5720+ open IfNotFound
5721+ switch Array.find(arr, f) {
5722+ | None =>
5723+ switch ifNotFound {
5724+ | Raise => failwith("No matching item found")
5725+ | ReturnNone => None
5726+ | DefaultTo(x) => x
5727+ }
5728+ | Some(x) =>
5729+ switch ifNotFound {
5730+ | ReturnNone => Some(x)
5731+ | Raise => x
5732+ | DefaultTo(_) => x
5733+ }
5734+ }
5735+}
5736+```
5737+
5738+## Hide and recover Type information Dynamically
5739+
5740+In an advanced case that combines the above techniques, we can use GADTs to selectively hide and recover type information. This helps us create more generic types.
5741+The below example defines a `num` type similar to our above addition example, but this lets us use `int` and `float` arrays
5742+interchangeably, hiding the implementation type rather than exposing it. This is similar to a regular variant. However, it is a tuple including embedding a `numTy` and another value.
5743+`numTy` serves as a type-witness, making it
5744+possible to recover type information that was hidden dynamically. Matching on `numTy` will "reveal" the type of the other value in the pair. We can use this to write a generic sum function over arrays of numbers:
5745+
5746+```res nocheck
5747+type rec numTy<'a> =
5748+ | Int: numTy<int>
5749+ | Float: numTy<float>
5750+and num = Num(numTy<'a>, 'a): num
5751+and num_array = Narray(numTy<'a>, array<'a>): num_array
5752+
5753+let addInt = (x, y) => x + y
5754+let addFloat = (x: float, y: float) => x + y
5755+
5756+let sum = (Narray(witness, array)) => {
5757+ switch witness {
5758+ | Int => Num(Int, array->Array.reduce(0, addInt))
5759+ | Float => Num(Float, array->Array.reduce(0., addFloat))
5760+ }
5761+}
5762+```
5763+
5764+## A Practical Example -- writing bindings:
5765+
5766+Javascript libraries that are highly polymorphic or use inheritance can benefit hugely from GADTs, but they can be useful for bindings even in other cases. The following examples are writing bindings to a simplified
5767+of Node's `Stream` API.
5768+
5769+This API has a method for binding event handlers, `on`. This takes an event and a callback. The callback accepts different parameters
5770+depending on which event we are binding to. A naive implementation might look similar to this, defining a
5771+separate method for each stream event to wrap the unsafe version of `on`.
5772+
5773+{/* TODO: fix this example, it has an error */}
5774+
5775+```res nocheck
5776+module Stream = {
5777+ type t
5778+
5779+ @new @module("node:http") external make: unit => t = "stream"
5780+
5781+ @send external on : (stream, string, 'a) => unit
5782+ let onEnd = (stream, callback: unit=> unit) => stream->on("end", callback)
5783+ let onData = (stream, callback: ('a => 'b)) => stream->on("", callback)
5784+ // etc. ...
5785+}
5786+```
5787+
5788+Not only is this quite tedious to write and quite ugly, but we gain very little in return. The function wrappers even add performance overhead, so we are losing on all fronts. If we define subtypes of
5789+Stream like `Readable` or `Writable`, which have all sorts of special interactions with the callback that jeopardize our type-safety, we are going to be in even deeper trouble.
5790+
5791+Instead, we can use the same GADT technique that let us vary return type to vary the input type.
5792+Not only are we able to now just use a single method, but the compiler will guarantee we are always using the correct callback type for the given event. We simply define an event GADT which specifies
5793+the type signature of the callback and pass this instead of a plain string.
5794+
5795+Additionally, we use some type parameters to represent the different types of Streams.
5796+
5797+This example is complex, but it enforces tons of useful rules. The wrong event can never be used
5798+with the wrong callback, but it also will never be used with the wrong kind of stream. The compiler will for example complain if we try to use a `Pipe` event with anything other than a `writable` stream.
5799+
5800+The real magic happens in the signature of `on`. Read it carefully, and then look at the examples and try to
5801+follow how the type variables are getting filled in, write it out on paper what each type variable is equal
5802+to if you need and it will soon become clear.
5803+
5804+{/* TODO: fix this example, it has an error */}
5805+
5806+```res nocheck
5807+
5808+module Stream = {
5809+ type t<'a>
5810+
5811+ type writable
5812+ type readable
5813+
5814+ type buffer = {buffer: ArrayBuffer.t}
5815+
5816+ @unboxed
5817+ type chunk =
5818+ | Str(string)
5819+ // Node uses actually its own buffer type, but for the tutorial we are using the stdlib's buffer type.
5820+ | Buf(buffer)
5821+
5822+ type rec event<_, _> =
5823+ // "as" here is setting the runtime representation of our constructor
5824+ | @as("pipe") Pipe: event<writable, t<readable> => unit>
5825+ | @as("end") End: event<'inputStream, option<chunk> => unit>
5826+ | @as("data") Data: event<readable, chunk => unit>
5827+
5828+ @new @module("node:http") external make: unit => t<'a> = "Stream"
5829+
5830+ @send
5831+ external on: (t<'inputStream>, event<'inputStream, 'callback>, 'callback) => unit = "on"
5832+
5833+}
5834+
5835+let writer = Stream.Writable.make()
5836+let reader = Stream.Readable.make()
5837+// Types will be correctly inferred for each callback, based on the event parameter provided
5838+writer->Stream.on(Pipe, r => {
5839+ Console.log("Piping has started")
5840+
5841+ r->Stream.on(Data, chunk =>
5842+ switch chunk {
5843+ | Stream.Str(s) => Console.log(s)
5844+ | Stream.Buf(buffer) => Console.log(buffer)
5845+ }
5846+ )
5847+})
5848+
5849+writer->Stream.on(End, _ => Console.log("End reached"))
5850+
5851+```
5852+
5853+This example is only over a tiny, imaginary subset of Node's Stream API, but it shows a real-life example
5854+where GADTs are all but indispensable.
5855+
5856+## Conclusion
5857+
5858+While GADTs can make your types extra-expressive and provide more safety, with great power comes great
5859+responsibility. Code that uses GADTs can sometimes be too clever for its own good. The type errors you
5860+encounter will be more difficult to understand, and the compiler sometimes requires extra help to properly
5861+type your code.
5862+
5863+However, there are definite situations where GADTs are the _right_ decision
5864+and will _simplify_ your code and help you avoid bugs, even rendering some bugs impossible. The `Stream` example above is a good example where the "simpler" alternative of using regular variants or even strings
5865+would lead to a much more complex and error prone interface.
5866+
5867+Ordinary variants are not necessarily _simple_ therefore, and neither are GADTs necessarily _complex_.
5868+The choice is rather which tool is the right one for the job. When your logic is complex, the highly expressive nature of GADTs can make it simpler to capture that logic.
5869+When your logic is simple, it's best to reach for a simpler tool and avoid the cognitive overhead.
5870+The only way to get good at identifying which tool to use in a given situation is to practice and experiment with both.
5871+
5872+---
5873+title: "Generate Converters & Helpers"
5874+description: "All about the @deriving decorator, and how to generate code from types"
5875+canonical: "/docs/manual/generate-converters-accessors"
5876+section: "JavaScript Interop"
5877+order: 12
5878+---
5879+
5880+# Generate Converters & Helpers
5881+
5882+**Note**: if you're looking for:
5883+
5884+- `@deriving(jsConverter)` for records
5885+- `@deriving({jsConverter: newType})` for records
5886+- `@deriving(abstract)` for records
5887+- `@deriving(jsConverter)` for plain and polymorphic variants
5888+
5889+These particular ones are no longer needed. Select a doc version lower than `9.0` in the sidebar to see their old docs.
5890+
5891+{/* TODO: genType */}
5892+
5893+When using ReScript, you will sometimes come into situations where you want to
5894+
5895+- Automatically generate functions that convert between ReScript's internal and JS runtime values (e.g. variants).
5896+- Convert a record type into an abstract type with generated creation, accessor and method functions.
5897+- Generate some other helper functions, such as functions from record attribute names.
5898+
5899+You can use the `@deriving` decorator for different code generation scenarios. All different options and configurations will be discussed on this page.
5900+
5901+**Note:** Please be aware that extensive use of code generation might make it harder to understand your programs (since the code being generated is not visible in the source code, and you just need to know what kind of functions / values a decorator generates).
5902+
5903+## Generate Functions & Plain Values for Variants
5904+
5905+Use `@deriving(accessors)` on a variant type to create accessor functions for its constructors.
5906+
5907+<CodeTab labels={["ReScript", "JS Output"]}>
5908+
5909+```res
5910+@deriving(accessors)
5911+type action =
5912+ | Click
5913+ | Submit(string)
5914+ | Cancel;
5915+```
5916+
5917+```js
5918+function submit(param_0) {
5919+ return {
5920+ TAG: "Submit",
5921+ _0: param_0,
5922+ };
5923+}
5924+
5925+let click = "Click";
5926+
5927+let cancel = "Cancel";
5928+
5929+export { click, submit, cancel };
5930+```
5931+
5932+</CodeTab>
5933+
5934+Variants constructors with payloads generate functions, payload-less constructors generate plain integers (the internal representation of variants).
5935+
5936+**Note**:
5937+
5938+- The generated accessors are lower-cased.
5939+- You can now use these helpers on the JavaScript side! But don't rely on their actual values please.
5940+
5941+### Usage
5942+
5943+```res nocheck
5944+let s = submit("hello"); /* gives Submit("hello") */
5945+```
5946+
5947+This is useful:
5948+
5949+- When you're passing the accessor function as a higher-order function (which plain variant constructors aren't).
5950+- When you'd like the JS side to use these values & functions opaquely and pass you back a variant constructor (since JS has no such thing).
5951+
5952+Please note that in case you just want to _pipe a payload into a constructor_, you don't need to generate functions for that. Use the `->` syntax instead, e.g. `"test"->Submit`.
5953+
5954+## Generate Field Accessors for Records
5955+
5956+Use `@deriving(accessors)` on a record type to create accessors for its record field names.
5957+
5958+<CodeTab labels={["ReScript", "JS Output"]}>
5959+
5960+```res
5961+@deriving(accessors)
5962+type pet = {name: string}
5963+
5964+let pets = [{name: "bob"}, {name: "bob2"}]
5965+
5966+pets
5967+ ->Array.map(name)
5968+ ->Array.joinWith("&")
5969+ ->Console.log
5970+```
5971+
5972+```js
5973+function name(param) {
5974+ return param.name;
5975+}
5976+
5977+let pets = [
5978+ {
5979+ name: "bob",
5980+ },
5981+ {
5982+ name: "bob2",
5983+ },
5984+];
5985+
5986+console.log(pets.map(name).join("&"));
5987+
5988+export { name, pets };
5989+```
5990+
5991+</CodeTab>
5992+
5993+---
5994+title: "Import & Export"
5995+description: "Importing / exporting in ReScript modules"
5996+canonical: "/docs/manual/import-export"
5997+section: "Language Features"
5998+order: 25
5999+---
6000+
6001+# Import & Export
6002+
6003+## Import a Module/File
6004+
6005+Unlike JavaScript, ReScript doesn't have or need import statements:
6006+
6007+<CodeTab labels={["ReScript", "JS Output"]}>
6008+
6009+```res nocheck
6010+// Inside School.res
6011+let studentMessage = Student.message
6012+```
6013+
6014+```js
6015+var Student = require("./Student.res.js");
6016+var studentMessage = Student.message;
6017+```
6018+
6019+</CodeTab>
6020+
6021+The above code refers to the `message` binding in the file `Student.res`. Every ReScript file is also a module, so accessing another file's content is the same as accessing another module's content!
6022+
6023+A ReScript project's file names need to be unique.
6024+
6025+## Export Stuff
6026+
6027+By default, every file's type declaration, binding and module is exported, aka publicly usable by another file. **This also means those values, once compiled into JS, are immediately usable by your JS code**.
6028+
6029+To only export a few selected things, use a `.resi` [interface file](./module.mdx#signatures).
6030+
6031+## Work with JavaScript Import & Export
6032+
6033+To see how to import JS modules and export stuff for JS consumption, see the JavaScript Interop section's [Import from/Export to JS](./import-from-export-to-js.mdx).
6034+
6035+---
6036+title: "Import from / Export to JS"
6037+description: "Importing / exporting JS module content in ReScript"
6038+canonical: "/docs/manual/import-from-export-to-js"
6039+section: "JavaScript Interop"
6040+order: 7
6041+---
6042+
6043+# Import from/Export to JS
6044+
6045+You've seen how ReScript's idiomatic [Import & Export](./import-export.mdx) works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.
6046+
6047+If you're looking for react-specific interop guidance, check out the [React JS Interop guide](../react/import-export-reactjs.mdx).
6048+
6049+**Tip**: keep your compiled JS output open in a tab to verify the generated import/export code.
6050+
6051+In short: **make sure your bindings below output what you'd have manually written in JS**.
6052+
6053+## Output Format
6054+
6055+We support 2 JavaScript import/export formats:
6056+
6057+- JavaScript module: `import * from 'MyReScriptFile'` and `export let ...`.
6058+- CommonJS: `require('myFile')` and `module.exports = ...`.
6059+
6060+The format is [configurable in via `rescript.json`](./build-configuration.mdx#package-specs).
6061+
6062+## Import From JavaScript
6063+
6064+### Import a JavaScript Module's Named Export
6065+
6066+Use the `module` [external](./external.mdx):
6067+
6068+<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>
6069+
6070+```res
6071+// Import nodejs' path.dirname
6072+@module("path") external dirname: string => string = "dirname"
6073+let root = dirname("/User/github") // returns "User"
6074+```
6075+
6076+```js
6077+import * as Path from "path";
6078+
6079+let root = Path.dirname("/User/github");
6080+
6081+export { root };
6082+```
6083+
6084+```js
6085+var Path = require("path");
6086+var root = Path.dirname("/User/github");
6087+
6088+exports.root = root;
6089+```
6090+
6091+</CodeTab>
6092+
6093+Here's what the `external` does:
6094+
6095+- `@module("path")`: pass the name of the JS module; in this case, `"path"`. The string can be anything: `"./src/myJsFile"`, `"@myNpmNamespace/myLib"`, etc.
6096+- `external`: the general keyword for declaring a value that exists on the JS side.
6097+- `dirname`: the binding name you'll use on the ReScript side.
6098+- `string => string`: the type signature of `dirname`. Mandatory for `external`s.
6099+- `= "dirname"`: the name of the variable inside the `path` JS module. There's repetition in writing the first and second `dirname`, because sometime the binding name you want to use on the ReScript side is different than the variable name the JS module exported.
6100+
6101+### Import a JavaScript Module As a Single Value
6102+
6103+By omitting the string argument to `module`, you bind to the whole JS module:
6104+
6105+<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>
6106+
6107+```res
6108+@module external leftPad: (string, int) => string = "./leftPad"
6109+let paddedResult = leftPad("hi", 5)
6110+```
6111+
6112+```js
6113+import * as LeftPad from "./leftPad";
6114+
6115+function leftPad(prim0, prim1) {
6116+ return LeftPad(prim0, prim1);
6117+}
6118+
6119+let paddedResult = LeftPad("hi", 5);
6120+
6121+export { leftPad, paddedResult };
6122+```
6123+
6124+```js
6125+var LeftPad = require("./leftPad");
6126+var paddedResult = LeftPad("hi", 5);
6127+```
6128+
6129+</CodeTab>
6130+
6131+Depending on whether you're compiling ReScript to JavaScript module or CommonJS, **this feature will generate subtly different code**. Please check both output tabs to see the difference. The JavaScript module output here would be wrong!
6132+
6133+### Import an `default` Export
6134+
6135+Use the value `default` on the right hand side:
6136+
6137+<CodeTab labels={["ReScript", "JS Output (Module)"]}>
6138+
6139+```res
6140+@module("./student") external studentName: string = "default"
6141+Console.log(studentName)
6142+```
6143+
6144+```js
6145+import Student from "./student";
6146+
6147+let studentName = Student;
6148+
6149+console.log(studentName);
6150+
6151+export { studentName };
6152+```
6153+
6154+</CodeTab>
6155+
6156+### Use Import Attributes
6157+
6158+**Since 11.1**
6159+
6160+[Import attributes](https://github.com/tc39/proposal-import-attributes) can be used in ReScript, as long as ReScript is configured to output JavaScript module. You do that by passing configuration to the `@module` attribute:
6161+
6162+<CodeTab labels={["ReScript", "JS Output (Module)"]}>
6163+```rescript
6164+@module({from: "./myJson.json", with: {type_: "json", \"some-exotic-identifier": "someValue"}})
6165+external myJson: JSON.t = "default"
6166+
6167+Console.log(myJson)
6168+
6169+````
6170+
6171+```javascript
6172+import MyJsonJson from "./myJson.json" with {"type": "json", "some-exotic-identifier": "someValue"};
6173+
6174+var myJson = MyJsonJson;
6175+
6176+console.log(myJson);
6177+````
6178+
6179+</CodeTab>
6180+
6181+This above imports the local `./myJson.json` file, adding import attributes.
6182+
6183+This is how it works:
6184+
6185+1. Instead of passing a string or tuple to `@module`, pass a record.
6186+2. This record should have a `from` key. The value of that is where you want the module to be imported from (just like the regular string to `@module` is).
6187+3. It should also have a `with` key, with another record where you put all the import attributes you want emitted.
6188+
6189+Notice `\"some-exotic-identifier"` - you'll need to escape any key that's not a valid ReScript record key.
6190+Also notice `type_`. Since `type` is a reserved keyword in ReScript, you can use `type_` instead. It will be output as `type` in the JavaScript code.
6191+
6192+## Dynamic Import
6193+
6194+Leveraging JavaScript's [dynamic `import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) to reduce bundle size and lazy load code as needed is easy in ReScript. It's also a little bit more convenient than in regular JavaScript because you don't need to keep track of file paths manually with ReScript's module system.
6195+
6196+### Dynamically Importing Parts of a Module
6197+
6198+Use the `import` function to dynamically import a specific part of a module. Put whatever `let` binding you want to import in there, and you'll get a `promise` back resolving to that specific binding.
6199+
6200+Let's look at an example. Imagine the following file `MathUtils.res`:
6201+
6202+```rescript
6203+let add = (a, b) => a + b
6204+let sub = (a, b) => a - b
6205+```
6206+
6207+Now let's dynamically import the add function in another module, e.g. `App.res`:
6208+
6209+<CodeTab labels={["ReScript", "JS Output (Module)"]}>
6210+```rescript
6211+// App.res
6212+let main = async () => {
6213+ let add = await import(MathUtils.add)
6214+ let onePlusOne = add(1, 1)
6215+
6216+Console.log(onePlusOne)
6217+}
6218+
6219+````
6220+```javascript
6221+async function main() {
6222+ var add = await import("./MathUtils.mjs").then(function(m) {
6223+ return m.add;
6224+ });
6225+
6226+ var onePlusOne = add(1, 1);
6227+ console.log(onePlusOne);
6228+}
6229+````
6230+
6231+</CodeTab>
6232+
6233+### Dynamically Importing an Entire Module
6234+
6235+The syntax for importing a whole module looks a little different, since we are operating on the module syntax level; instead of using `import`, you may simply `await` the module itself:
6236+
6237+<CodeTab labels={["ReScript", "JS Output (Module)"]}>
6238+```rescript
6239+// App.res
6240+let main = async () => {
6241+ module Utils = await MathUtils
6242+
6243+let twoPlusTwo = Utils.add(2, 2)
6244+Console.log(twoPlusTwo)
6245+}
6246+
6247+````
6248+```javascript
6249+async function main() {
6250+ var Utils = await import("./MathUtils.mjs");
6251+
6252+ var twoPlusTwo = Utils.add(2, 2);
6253+ console.log(twoPlusTwo);
6254+}
6255+````
6256+
6257+</CodeTab>
6258+
6259+## Export To JavaScript
6260+
6261+### Export a Named Value
6262+
6263+As mentioned in ReScript's idiomatic [Import & Export](./import-export.mdx), every let binding and module is exported by default to other ReScript modules (unless you use a `.resi` [interface file](./module.mdx#signatures)). If you open up the compiled JS file, you'll see that these values can also directly be used by a _JavaScript_ file too.
6264+
6265+### Export a `default` Value
6266+
6267+If your JS project uses JavaScript module, you're likely exporting & importing some default values:
6268+
6269+```js
6270+// student.js
6271+export default name = "Al";
6272+```
6273+
6274+```js
6275+// teacher.js
6276+import studentName from "student.js";
6277+```
6278+
6279+A JavaScript default export is really just syntax sugar for a named export implicitly called `default` (now you know!). So to export a default value from ReScript, you can just do:
6280+
6281+<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>
6282+
6283+```res
6284+// ReScriptStudent.res
6285+let default = "Bob"
6286+```
6287+
6288+```js
6289+let $$default = "Bob";
6290+
6291+export { $$default as default };
6292+```
6293+
6294+```js
6295+var $$default = "Bob";
6296+
6297+export { $$default, $$default as default };
6298+```
6299+
6300+</CodeTab>
6301+
6302+You can then import this default export as usual on the JS side:
6303+
6304+```js
6305+// teacher2.js
6306+import studentName from "ReScriptStudent.js";
6307+```
6308+
6309+If your JavaScript's default import is transpiled by Babel/Webpack/Jest into CommonJS `require`s, we've taken care of that too! See the CommonJS output tab for `__esModule`.
6310+
6311+---
6312+title: "Inlining Constants"
6313+description: "Inlining constants"
6314+canonical: "/docs/manual/inlining-constants"
6315+section: "JavaScript Interop"
6316+order: 10
6317+---
6318+
6319+# Inlining Constants
6320+
6321+Sometimes, in the JavaScript output, you might want a certain value to be forcefully inlined. For example:
6322+
6323+```js
6324+if (process.env.mode === "development") {
6325+ console.log("Dev-only code here!");
6326+}
6327+```
6328+
6329+The reason is that your JavaScript bundler (e.g. Webpack) might turn that into:
6330+
6331+```js
6332+if ("production" === "development") {
6333+ console.log("Dev-only code here!");
6334+}
6335+```
6336+
6337+Then your subsequent Uglifyjs optimization would remove that entire `if` block. This is how projects like ReactJS provide a development mode code with plenty of dev warnings, while ensuring that the uglified (minified) production code is free of those expensive blocks.
6338+
6339+So, in ReScript, producing that example `if (process.env.mode === 'development')` output is important. This first try doesn't work:
6340+
6341+<CodeTab labels={["ReScript", "JS Output"]}>
6342+
6343+```res
6344+@val external process: 'a = "process"
6345+
6346+let mode = "development"
6347+
6348+if (process["env"]["mode"] === mode) {
6349+ Console.log("Dev-only code here!")
6350+}
6351+```
6352+
6353+```js
6354+let mode = "development";
6355+
6356+if (process.env.mode === mode) {
6357+ console.log("Dev-only code here!");
6358+}
6359+
6360+export { mode };
6361+```
6362+
6363+</CodeTab>
6364+
6365+The JS output shows `if (process.env.mode === mode)`, which isn't what we wanted. To inline `mode`'s value, use `@inline`:
6366+
6367+<CodeTab labels={["ReScript", "JS Output"]}>
6368+
6369+```res
6370+@val external process: 'a = "process"
6371+
6372+@inline
6373+let mode = "development"
6374+
6375+if (process["env"]["mode"] === mode) {
6376+ Console.log("Dev-only code here!")
6377+}
6378+```
6379+
6380+```js
6381+if (process.env.mode === "development") {
6382+ console.log("Dev-only code here!");
6383+}
6384+```
6385+
6386+</CodeTab>
6387+
6388+Now your resulting JS code can pass through Webpack and Uglifyjs like the rest of your JavaScript code, and that whole `console.log` can be removed.
6389+
6390+The inlining currently only works for **string, float and boolean**.
6391+
6392+## Tips & Tricks
6393+
6394+This is **not** an optimization. This is an edge-case feature for folks who absolutely need particular values inlined for a JavaScript post-processing step, like conditional compilation. Beside the difference in code that the conditional compilation might end up outputting, there's no performance difference between inlining and not inlining simple values in the eyes of a JavaScript engine.
6395+
6396+---
6397+title: "Installation"
6398+description: "ReScript installation and setup instructions"
6399+canonical: "/docs/manual/installation"
6400+section: "Overview"
6401+order: 2
6402+---
6403+
6404+# Installation
6405+
6406+## Prerequisites
6407+
6408+<div className="install-list">
6409+- [Node.js](https://nodejs.org/) version >= 22
6410+- One of the following package managers:
6411+ - [npm](https://docs.npmjs.com/cli/) (comes with Node.js)
6412+ - [yarn](https://yarnpkg.com/)
6413+ - yarn versions >1 need to set `nodeLinker: node-modules` in `.yarnrc.yml`
6414+ - [pnpm](https://pnpm.io/)
6415+ - [bun](https://bun.sh/)
6416+ - [deno](http://deno.com/)
6417+ - Configure `"nodeModulesDir": "auto"` in `deno.json`
6418+</div>
6419+
6420+## New Project
6421+
6422+The fastest and easiest way to spin up a new ReScript project is with the [create-rescript-app](https://github.com/rescript-lang/create-rescript-app) project generator. This will get you started with a fresh Next.js or Vite app with React and Tailwind CSS.
6423+
6424+You can start it with any of the aforementioned package managers or `npx`.
6425+
6426+<CodeTab labels={["npm", "npx", "yarn", "pnpm", "bun"]}>
6427+
6428+```sh example
6429+npm create rescript-app@latest
6430+```
6431+
6432+```sh
6433+npx create-rescript-app
6434+```
6435+
6436+```sh
6437+yarn create rescript-app
6438+```
6439+
6440+```sh
6441+pnpm create rescript-app
6442+```
6443+
6444+```sh
6445+bun create rescript-app
6446+```
6447+
6448+</CodeTab>
6449+
6450+- Follow the steps of the setup.
6451+- Trigger a ReScript build:
6452+
6453+ ```sh
6454+ npm run res:build
6455+ ```
6456+- If you selected the "basic" template, simply run it with:
6457+
6458+ ```sh
6459+ node src/Demo.res.mjs
6460+ ```
6461+
6462+That compiles your ReScript into JavaScript, then uses Node.js to run said JavaScript.
6463+
6464+**When taking your first steps with ReScript, we recommend you use our unique workflow of keeping a tab open for the generated JS file** (`.res.js`/`.res.mjs`), so that you can learn how ReScript transforms into JavaScript. Not many languages output clean JavaScript code you can inspect and learn from! With our [VS Code extension](https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode), use the command "ReScript: Open the compiled JS file for this implementation file" to open the generated JS file for the currently active ReScript source file.
6465+
6466+During development, instead of running `npm run res:build` each time to compile, use `npm run res:dev` to start a watcher that recompiles automatically after file changes.
6467+
6468+## Integrate Into an Existing JS Project
6469+
6470+If you already have a JavaScript project into which you'd like to add ReScript you can do that in the following ways:
6471+
6472+### Quick Setup
6473+
6474+In the root directory of your project, execute:
6475+
6476+<CodeTab labels={["npm", "npx", "yarn", "pnpm", "bun"]}>
6477+
6478+```sh
6479+npm create rescript-app@latest
6480+```
6481+
6482+```sh
6483+npx create-rescript-app
6484+```
6485+
6486+```sh
6487+yarn create rescript-app
6488+```
6489+
6490+```sh
6491+pnpm create rescript-app
6492+```
6493+
6494+```sh
6495+bun create rescript-app
6496+```
6497+
6498+</CodeTab>
6499+
6500+`create-rescript-app` will tell you that a `package.json` file has been detected and ask you if it should install ReScript into your project. Just follow the steps accordingly.
6501+
6502+### Manual Setup
6503+
6504+- Install ReScript locally:
6505+
6506+ <CodeTab labels={["npm", "yarn", "pnpm", "bun", "deno"]}>
6507+
6508+ ```sh
6509+ npm install rescript
6510+ ```
6511+
6512+ ```sh
6513+ yarn add rescript
6514+ ```
6515+
6516+ ```sh
6517+ pnpm install rescript
6518+ ```
6519+
6520+ ```sh
6521+ bun install rescript
6522+ ```
6523+
6524+ ```sh
6525+ // you will need deno configured to have a node_modules folder
6526+ deno install npm:rescript --allow-scripts
6527+ ```
6528+
6529+ </CodeTab>
6530+
6531+ <Info>
6532+ **pnpm users:** ReScript-compiled JS imports from `@rescript/runtime` directly, but pnpm's strict isolation does not expose transitive dependencies at the app root. Either install the runtime as a direct dependency (`pnpm add @rescript/runtime`), or hoist it by adding the following to `pnpm-workspace.yaml`:
6533+
6534+ ```yaml
6535+ publicHoistPattern:
6536+ - "*@rescript/runtime*"
6537+ ```
6538+ </Info>
6539+
6540+- Create a ReScript build configuration file (called `rescript.json`) at the root:
6541+ ```json
6542+ {
6543+ "name": "your-project-name",
6544+ "sources": [
6545+ {
6546+ "dir": "src", // update this to wherever you're putting ReScript files
6547+ "subdirs": true
6548+ }
6549+ ],
6550+ "package-specs": [
6551+ {
6552+ "module": "esmodule",
6553+ "in-source": true
6554+ }
6555+ ],
6556+ "suffix": ".res.js"
6557+ }
6558+ ```
6559+ See [Build Configuration](./build-configuration.mdx) for more details on `rescript.json`.
6560+- Add convenience `npm` scripts to `package.json`:
6561+ ```json
6562+ "scripts": {
6563+ "build:res": "rescript",
6564+ "dev:res": "rescript watch"
6565+ }
6566+ ```
6567+
6568+Since ReScript compiles to clean readable JS files, the rest of your existing toolchain (e.g. Vite, Rspack, Rollup) should just work!
6569+
6570+Helpful guides:
6571+
6572+- [Converting from JS](./converting-from-js.mdx).
6573+- [Shared Data Types](./shared-data-types.mdx).
6574+- [Import from/Export to JS](./import-from-export-to-js.mdx).
6575+
6576+### Integrate with a ReactJS Project
6577+
6578+To start a [rescript-react](../react/introduction.mdx) app, or to integrate ReScript into an existing ReactJS app, follow the instructions [here](../react/installation.mdx).
6579+
6580+---
6581+title: "Interop Cheatsheet"
6582+description: "Cheatsheet for various interop scenarios in ReScript"
6583+canonical: "/docs/manual/interop-cheatsheet"
6584+section: "JavaScript Interop"
6585+order: 1
6586+---
6587+
6588+# Interop Cheatsheet
6589+
6590+This is a glossary with examples. All the features are described by later pages.
6591+
6592+## List of Decorators
6593+
6594+> **Note:** In ReScript < 8.3, all our attributes started with the `bs.` prefix. This is no longer needed and our formatter automatically removes them in newer ReScript versions.
6595+
6596+{/* Synced from https://github.com/rescript-lang/syntax/blob/123760c5a264da5288eeee5213ddd25eb86d62fe/src/res_printer.ml#L19-L51 */}
6597+
6598+### Attributes
6599+
6600+- `@as`: [here](./attribute.mdx#usage), [here](./bind-to-js-function.mdx#fixed-arguments), [here](./bind-to-js-function.mdx#constrain-arguments-better) and [here](./generate-converters-accessors.mdx#usage-3)
6601+- [`@deriving`](./generate-converters-accessors.mdx#generate-functions--plain-values-for-variants)
6602+- [`@get`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
6603+- [`@get_index`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
6604+- [`@inline`](./inlining-constants.mdx)
6605+- [`@int`](./bind-to-js-function.mdx#constrain-arguments-better)
6606+- [`@module`](./import-from-export-to-js.mdx#import-a-javascript-modules-content)
6607+- [`@new`](./bind-to-js-object.mdx#bind-to-a-js-object-thats-a-class)
6608+- [`@optional`](./generate-converters-accessors.mdx#optional-labels)
6609+- [`@return`](./bind-to-js-function.mdx#function-nullable-return-value-wrapping)
6610+- `@send`: [here](./bind-to-js-function.mdx#object-method) and [here](./pipe.mdx#js-method-chaining)
6611+- [`@scope`](./bind-to-global-js-values.mdx#global-modules)
6612+- [`@set`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
6613+- [`@set_index`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
6614+- [`@variadic`](./bind-to-js-function.mdx#variadic-function-arguments)
6615+- [`@string`](./bind-to-js-function.mdx#constrain-arguments-better)
6616+- [`@this`](./bind-to-js-function.mdx#modeling-this-based-callbacks)
6617+- [`@uncurry`](./bind-to-js-function.mdx#extra-solution)
6618+- [`@unwrap`](./bind-to-js-function.mdx#trick-2-polymorphic-variant--bsunwrap)
6619+- [`@val`](./bind-to-global-js-values.mdx#global-modules)
6620+- [`@taggedTemplate`](./bind-to-js-function.mdx#tagged_template-functions)
6621+- [`@deprecated`](./attribute.mdx#usage)
6622+- [`genType`](https://github.com/reason-association/genType)
6623+- [`@JSX`](./jsx.mdx)
6624+- `@react.component`: [here](../react/introduction.mdx) and [here](https://github.com/reasonml/reason-react)
6625+- [`@warning`](./attribute.mdx#usage)
6626+- [`@unboxed`](./variant.mdx#untagged-variants)
6627+
6628+### Extension Points
6629+
6630+- [`%debugger`](./embed-raw-javascript.mdx#debugger)
6631+- [`%external`](./bind-to-global-js-values.mdx#special-global-values)
6632+- [`%raw`](./embed-raw-javascript.mdx#paste-raw-js-code)
6633+- [`%todo`](../../syntax-lookup/extension_todo.mdx)
6634+
6635+## Raw JS
6636+
6637+<CodeTab labels={["ReScript", "JS Output"]}>
6638+
6639+```res
6640+let add = %raw("(a, b) => a + b")
6641+%%raw("const a = 1")
6642+```
6643+
6644+```js
6645+let add = (a, b) => a + b;
6646+
6647+const a = 1;
6648+export { add };
6649+```
6650+
6651+</CodeTab>
6652+
6653+## Global Value
6654+
6655+<CodeTab labels={["ReScript", "JS Output"]}>
6656+
6657+```res
6658+@val external setTimeout: (unit => unit, int) => float = "setTimeout"
6659+```
6660+
6661+```js
6662+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
6663+```
6664+
6665+</CodeTab>
6666+
6667+## Global Module's Value
6668+
6669+<CodeTab labels={["ReScript", "JS Output"]}>
6670+
6671+```res
6672+@val @scope("Math")
6673+external random: unit => float = "random"
6674+
6675+let someNumber = random()
6676+
6677+@val @scope(("window", "location", "ancestorOrigins"))
6678+external length: int = "length"
6679+```
6680+
6681+```js
6682+let someNumber = Math.random();
6683+
6684+export { someNumber };
6685+```
6686+
6687+</CodeTab>
6688+
6689+## Nullable
6690+
6691+<CodeTab labels={["ReScript", "JS Output"]}>
6692+
6693+```res
6694+let a = Some(5) // compiles to 5
6695+let b = None // compiles to undefined
6696+```
6697+
6698+```js
6699+let a = 5;
6700+
6701+let b;
6702+
6703+export { a, b };
6704+```
6705+
6706+</CodeTab>
6707+
6708+Handling a value that can be `undefined` and `null`, by ditching the `option` type and using `Nullable.t`:
6709+
6710+<CodeTab labels={["ReScript", "JS Output"]}>
6711+
6712+```res
6713+let jsNull = Nullable.null
6714+let jsUndefined = Nullable.undefined
6715+let result1: Nullable.t<string> = Nullable.make("hello")
6716+let result2: Nullable.t<int> = Nullable.fromOption(Some(10))
6717+let result3: option<int> = Nullable.toOption(Nullable.make(10))
6718+```
6719+
6720+```js
6721+import * as Stdlib_Nullable from "@rescript/runtime/lib/es6/Stdlib_Nullable.js";
6722+import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
6723+
6724+let result2 = Stdlib_Nullable.fromOption(10);
6725+
6726+let jsNull = null;
6727+
6728+let jsUndefined;
6729+
6730+let result1 = "hello";
6731+
6732+let result3 = Primitive_option.fromNullable(10);
6733+
6734+export { jsNull, jsUndefined, result1, result2, result3 };
6735+```
6736+
6737+</CodeTab>
6738+
6739+## JS Object
6740+
6741+- [Bind to a JS object as a ReScript record](./bind-to-js-object.mdx#bind-to-record-like-js-objects).
6742+- [Bind to a JS object that acts like a hash map](./bind-to-js-object.mdx#bind-to-hash-map-like-js-object).
6743+- [Bind to a JS object that's a class](./bind-to-js-object.mdx#bind-to-a-js-object-thats-a-class).
6744+
6745+## Function
6746+
6747+### Object Method & Chaining
6748+
6749+<CodeTab labels={["ReScript", "JS Output"]}>
6750+
6751+```res
6752+@send external map: (array<'a>, 'a => 'b) => array<'b> = "map"
6753+@send external filter: (array<'a>, 'a => 'b) => array<'b> = "filter"
6754+[1, 2, 3]
6755+ ->map(a => a + 1)
6756+ ->filter(a => mod(a, 2) == 0)
6757+ ->Console.log
6758+```
6759+
6760+```js
6761+console.log([1, 2, 3].map((a) => (a + 1) | 0).filter((a) => a % 2 === 0));
6762+```
6763+
6764+</CodeTab>
6765+
6766+### Variadic Arguments
6767+
6768+<CodeTab labels={["ReScript", "JS Output"]}>
6769+
6770+```res
6771+@module("path") @variadic
6772+external join: array<string> => string = "join"
6773+```
6774+
6775+```js
6776+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
6777+```
6778+
6779+</CodeTab>
6780+
6781+### Tagged template functions
6782+
6783+<CodeTab labels={["ReScript", "JS Output"]}>
6784+
6785+```res
6786+// see https://bun.sh/docs/runtime/shell
6787+type result = {exitCode: int}
6788+@module("bun") @taggedTemplate
6789+external sh: (array<string>, array<string>) => promise<result> = "$"
6790+
6791+let filename = "index.res"
6792+let result = await sh`ls ${filename}`
6793+```
6794+
6795+```js
6796+import * as $$Bun from "bun";
6797+
6798+let filename = "index.res";
6799+
6800+let result = await $$Bun.$`ls ${filename}`;
6801+
6802+export { filename, result };
6803+```
6804+
6805+</CodeTab>
6806+
6807+### Polymorphic Function
6808+
6809+<CodeTab labels={["ReScript", "JS Output"]}>
6810+
6811+```res
6812+@module("Drawing") external drawCat: unit => unit = "draw"
6813+@module("Drawing") external drawDog: (~giveName: string) => unit = "draw"
6814+```
6815+
6816+```js
6817+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
6818+```
6819+
6820+</CodeTab>
6821+
6822+<CodeTab labels={["ReScript", "JS Output"]}>
6823+
6824+```res
6825+@val
6826+external padLeft: (
6827+ string,
6828+ @unwrap [
6829+ | #Str(string)
6830+ | #Int(int)
6831+ ])
6832+ => string = "padLeft"
6833+
6834+padLeft("Hello World", #Int(4))
6835+padLeft("Hello World", #Str("Message from ReScript: "))
6836+```
6837+
6838+```js
6839+padLeft("Hello World", 4);
6840+
6841+padLeft("Hello World", "Message from ReScript: ");
6842+```
6843+
6844+</CodeTab>
6845+
6846+## JS Module Interop
6847+
6848+[See here](./import-from-export-to-js.mdx)
6849+
6850+## Dangerous Type Cast
6851+
6852+Final escape hatch converter. Do not abuse.
6853+
6854+<CodeTab labels={["ReScript", "JS Output"]}>
6855+
6856+```res
6857+external convertToFloat: int => float = "%identity"
6858+let age = 10
6859+let gpa = 2.1 + convertToFloat(age)
6860+```
6861+
6862+```js
6863+let gpa = 2.1 + 10;
6864+
6865+let age = 10;
6866+
6867+export { age, gpa };
6868+```
6869+
6870+</CodeTab>
6871+
6872+---
6873+title: "Interop with JS Build Systems"
6874+description: "Documentation on how to interact with existing JS build systems"
6875+canonical: "/docs/manual/interop-with-js-build-systems"
6876+section: "Build System"
6877+order: 6
6878+---
6879+
6880+# Interop with JS Build Systems
6881+
6882+If you come from JS, chances are that you already have a build system in your existing project. Here's an overview of the role `rescript` would play in your build pipeline, if you want to introduce some ReScript code.
6883+
6884+> **Please** try not to wrap `rescript` into your own incremental build framework. ReScript's compilation is very hard to get right, and you'll inevitably run into stale or badly performing builds (therefore erasing much of our value proposition) if you create your own meta layer on top.
6885+
6886+## Popular JS Build Systems
6887+
6888+The JS ecosystem uses a few build systems: [vite](https://vite.dev/), [browserify](http://browserify.org/), [rollup](https://github.com/rollup/rollup), [webpack](https://webpack.js.org/), etc. The first one is probably the most popular of the four (as of 2025). These build systems do both the compilation and the linking (aka, bundling many files into one or few files).
6889+
6890+`rescript` only takes care of the compilation step; it maps one `.res`/`.resi` file into one JS output file. As such, in theory, no build system integration is needed from our side. From e.g. the webpack watcher's perspective, the JS files ReScript generates are almost equivalent to your hand-written JS files. We also recommend **that you initially check in those ReScript-generated JS files**, as this workflow means:
6891+
6892+- You can introduce ReScript silently into your codebase without disturbing existing infra.
6893+- You have a **visual** diff of the performance & correctness of your JS file when you update the `.res` files and the JS artifacts change.
6894+- You can let teammates hot-patch the JS files in emergency situations, without needing to first start learning ReScript.
6895+- You can remove ReScript completely from your codebase and things will still work (in case your company decides to stop using us for whatever reason).
6896+
6897+For what it's worth, you can also turn `rescript` into an automated step in your build pipeline, e.g. into a Webpack loader; but such approach is error-prone and therefore discouraged.
6898+
6899+### Tips & Tricks
6900+
6901+You can make ReScript JS files look even more idiomatic through the in-source + bs suffix config in `rescript.json`:
6902+
6903+```json
6904+{
6905+ "package-specs": {
6906+ "module": "commonjs", // or whatever module system your project uses
6907+ "in-source": true
6908+ },
6909+ "suffix": ".res.js"
6910+}
6911+```
6912+
6913+This will:
6914+
6915+- Generate the JS files alongside your ReScript source files.
6916+- Use the file extension `.res.js`, so that you can require these files on the JS side through `require('./MyFile.res.js')`, without needing a loader.
6917+
6918+## Use Loaders on ReScript Side
6919+
6920+"What if my build system uses a CSS/png/whatever loader and I'd like to use it in ReScript?"
6921+
6922+Loaders are indeed troublesome; in the meantime, please use e.g. `%raw("require('./myStyles.css')")` at the top of your file. This just uses [`raw`](./embed-raw-javascript.mdx) to compile the snippet into an actual JS require.
6923+
6924+## Getting Project's Dependencies
6925+
6926+`rescript` generates one `MyFile.d` file per `MyFile` source file; you'll find them in `lib/bs`. These are human readable, machine-friendly list of the dependencies of said `MyFile`. You can read into them for your purpose (though mind the IO overhead). Use these files instead of creating your own dependency graph; we did the hard work of tracking the dependencies as best as possible (including inner modules, `open`s, module names overlap, etc).
6927+
6928+## Run Script Per File Built
6929+
6930+See [js-post-build](./build-configuration.mdx#js-post-build). Though please use it sparingly; if you hook up a node.js script after each file built, you'll incur the node startup time per file!
6931+
6932+---
6933+title: "Introduction"
6934+description: "Introduction to the ReScript programming language"
6935+canonical: "/docs/manual/introduction"
6936+section: "Overview"
6937+order: 1
6938+---
6939+
6940+# ReScript
6941+
6942+ReScript is a robustly typed language that compiles to efficient and human-readable JavaScript. It comes with a lightning fast compiler toolchain that scales to any codebase size.
6943+
6944+## JavaScript Interop
6945+
6946+ReScript compiles to clean, readable, and performant JavaScript, directly runnable in browsers and Node. Your existing package managers, bundlers, frameworks, and test runners all work with ReScript.
6947+
6948+Your existing knowledge of web development transfers to ReScript projects.
6949+
6950+If you are coming from JavaScript, start with [ReScript for JavaScript Developers](./rescript-for-javascript-developers.mdx) for a quick syntax guide.
6951+
6952+ReScript code can be [imported into JavaScript code](./import-from-export-to-js.mdx#export-to-javascript), can [generate types for TypeScript](./typescript-integration.mdx), and ReScript can [import code written in JavaScript or TypeScript](./import-from-export-to-js.mdx#import-from-javascript).
6953+
6954+## Type System
6955+
6956+- Is deliberately curated to be a simple subset most folks will have an easier time to use.
6957+- Sound type system. If a type isn't marked as nullable, the value will never be `undefined`. **ReScript code has no null/undefined errors**.
6958+- No configuration needed. The type system behaves the same way in every project.
6959+- Runs extremely fast precisely thanks to its simplicity and curation. It's one of the fastest compiler & build system toolchains for JavaScript development.
6960+- **Doesn't need type annotations**. Annotate as much or as little as you'd like. The types are inferred by the language (and, again, are guaranteed correct).
6961+
6962+## Compiler
6963+
6964+### Compiles to Optimized JavaScript
6965+
6966+ReScript's type system and compiler generate JavaScript that is performant by default, taking advantage of Just-In-Time optimizations (hidden classes, inline caching, avoiding deopts, etc).
6967+
6968+### Tiny JS Output
6969+
6970+A `Hello world` ReScript program generates **20 bytes** of JS code. Additionally, the standard library pieces you require in are only included when needed.
6971+
6972+### Fast Iteration Loop
6973+
6974+ReScript's build time is **one or two orders of magnitude** faster than alternatives. In its watcher mode, the build system usually finishes before you switch screen from the editor to the terminal tab (two digits of milliseconds). A fast iteration cycle reduces the need of keeping one's mental state around longer; this in turn allows one to stay in the flow longer and more often.
6975+
6976+### Readable Output
6977+
6978+ReScript's JS output is very readable. This is especially important while learning, where users might want to understand how the code's compiled, and to audit for bugs.
6979+
6980+This characteristic, combined with a fully-featured JS interop system, allows ReScript code to be inserted into an existing JavaScript codebase almost unnoticed.
6981+
6982+### Preservation of Code Structure
6983+
6984+ReScript maps one source file to one JavaScript output file. This eases the integration of existing tools such as bundlers and test runners. You can even start writing a single file without much change to your build setup. Each file's code structure is approximately preserved, too.
6985+
6986+### High Quality Dead Code Elimination
6987+
6988+The JavaScript ecosystem is very reliant on dependencies. Shipping the final product inevitably drags in a huge amount of code, lots of which the project doesn't actually use. These regions of dead code impact loading, parsing and interpretation speed. ReScript provides powerful dead code elimination at all levels:
6989+
6990+- Function- and module-level code elimination is facilitated by the well-engineered type system and purity analysis.
6991+- At the global level, ReScript generates code that is naturally friendly to dead code elimination done by bundling tools such as [Rollup](https://github.com/rollup/rollup) and [Closure Compiler](https://developers.google.com/closure/compiler/), after its own sophisticated elimination pass.
6992+- The same applies for ReScript's own tiny runtime (which is written in ReScript itself).
6993+
6994+---
6995+title: "JSON"
6996+description: "Interacting with JSON in ReScript"
6997+canonical: "/docs/manual/json"
6998+section: "JavaScript Interop"
6999+order: 9
7000+---
7001+
7002+# JSON
7003+
7004+## Parse
7005+
7006+Bind to JavaScript's `JSON.parse` and type the return value as the type you're expecting:
7007+
7008+<CodeTab labels={["ReScript", "JS Output"]}>
7009+
7010+```res
7011+// declare the shape of the json you're binding to
7012+type data = {names: array<string>}
7013+
7014+// bind to JS' JSON.parse
7015+@scope("JSON") @val
7016+external parseIntoMyData: string => data = "parse"
7017+
7018+let result = parseIntoMyData(`{"names": ["Luke", "Christine"]}`)
7019+let name1 = result.names[0]
7020+```
7021+
7022+```js
7023+let result = JSON.parse(`{"names": ["Luke", "Christine"]}`);
7024+
7025+let name1 = result.names[0];
7026+
7027+export { result, name1 };
7028+```
7029+
7030+</CodeTab>
7031+
7032+Where `data` can be any type you assume the JSON is. As you can see, this compiles to a straightforward `JSON.parse` call. As with regular JS, this is convenient, but has no guarantee that e.g. the data is correctly shaped, or even syntactically valid. Slightly dangerous.
7033+
7034+## Stringify
7035+
7036+Use [`JSON.stringify`](/docs/manual/api/stdlib/json#value-stringify) if your data is of type `JSON.t` or [`JSON.stringifyAny`](/docs/manual/api/stdlib/json#value-stringifyAny) if it is not.
7037+
7038+<CodeTab labels={["ReScript", "JS Output"]}>
7039+
7040+```res
7041+Console.log(JSON.stringifyAny(["Amy", "Joe"]))
7042+```
7043+
7044+```js
7045+console.log(JSON.stringify(["Amy", "Joe"]));
7046+```
7047+
7048+</CodeTab>
7049+
7050+## Import a JSON file
7051+
7052+Use the `@module` attribute to import JSON files directly.
7053+
7054+<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>
7055+
7056+```res
7057+@module external studentNames: JSON.t = "./students.json"
7058+Console.log(studentNames)
7059+```
7060+
7061+```js
7062+import * as StudentsJson from "./students.json";
7063+
7064+let studentNames = StudentsJson;
7065+
7066+console.log(studentNames);
7067+
7068+export { studentNames };
7069+```
7070+
7071+```js
7072+var StudentsJson = require("./students.json");
7073+
7074+var studentNames = StudentsJson;
7075+
7076+console.log(studentNames);
7077+```
7078+
7079+</CodeTab>
7080+
7081+## Advanced
7082+
7083+The generated types are [variants](./variant.mdx), and decoding them requires you to drill down as much
7084+
7085+---
7086+title: "JSX"
7087+description: "JSX syntax in ReScript and React"
7088+canonical: "/docs/manual/jsx"
7089+section: "Language Features"
7090+order: 18
7091+---
7092+
7093+# JSX
7094+
7095+Would you like some HTML syntax in your ReScript? If not, quickly skip over this section and pretend you didn't see anything!
7096+
7097+ReScript supports the JSX syntax, with some slight differences compared to the one in [ReactJS](https://facebook.github.io/react/docs/introducing-jsx.html). ReScript JSX isn't tied to ReactJS; they translate to normal function calls:
7098+
7099+**Note** for [ReScriptReact](../react/introduction.mdx) readers: this isn't what ReScriptReact turns JSX into, in the end. See Usage section for more info.
7100+
7101+## Capitalized
7102+
7103+<CodeTab labels={["ReScript", "JS Output"]}>
7104+
7105+```res nocheck
7106+<MyComponent name={"ReScript"} />
7107+```
7108+
7109+```js
7110+import * as JsxRuntime from "react/jsx-runtime";
7111+
7112+JsxRuntime.jsx(MyComponent, {
7113+ name: "ReScript",
7114+});
7115+```
7116+
7117+</CodeTab>
7118+
7119+becomes
7120+
7121+<CodeTab labels={["ReScript", "JS Output"]}>
7122+
7123+```res nocheck
7124+React.jsx(MyComponent.make, {name: {"ReScript"}})
7125+```
7126+
7127+```js
7128+import * as JsxRuntime from "react/jsx-runtime";
7129+
7130+JsxRuntime.jsx(MyComponent, {
7131+ name: "ReScript",
7132+});
7133+```
7134+
7135+</CodeTab>
7136+
7137+## Uncapitalized
7138+
7139+<CodeTab labels={["ReScript", "JS Output"]}>
7140+
7141+```res nocheck
7142+<div onClick={handler}> child1 child2 </div>
7143+```
7144+
7145+```js
7146+import * as JsxRuntime from "react/jsx-runtime";
7147+
7148+JsxRuntime.jsxs("div", {
7149+ children: [child1, child2],
7150+ onClick: handler,
7151+});
7152+```
7153+
7154+</CodeTab>
7155+
7156+becomes
7157+
7158+<CodeTab labels={["ReScript", "JS Output"]}>
7159+
7160+```res nocheck
7161+ReactDOM.jsxs("div", {onClick: {handler}, children: React.array([child1, child2])})
7162+```
7163+
7164+```js
7165+import * as JsxRuntime from "react/jsx-runtime";
7166+
7167+JsxRuntime.jsxs("div", {
7168+ children: [child1, child2],
7169+ onClick: handler,
7170+});
7171+```
7172+
7173+</CodeTab>
7174+
7175+## Fragment
7176+
7177+<CodeTab labels={["ReScript", "JS Output"]}>
7178+
7179+```res nocheck
7180+<> child1 child2 </>
7181+```
7182+
7183+```js
7184+import * as JsxRuntime from "react/jsx-runtime";
7185+
7186+JsxRuntime.jsxs(JsxRuntime.Fragment, {
7187+ children: [child1, child2],
7188+});
7189+```
7190+
7191+</CodeTab>
7192+
7193+becomes
7194+
7195+<CodeTab labels={["ReScript", "JS Output"]}>
7196+
7197+```res nocheck
7198+React.jsxs(React.jsxFragment, {children: React.array([child1, child2])})
7199+```
7200+
7201+```js
7202+import * as JsxRuntime from "react/jsx-runtime";
7203+
7204+JsxRuntime.jsxs(JsxRuntime.Fragment, {
7205+ children: [child1, child2],
7206+});
7207+```
7208+
7209+</CodeTab>
7210+
7211+### Children
7212+
7213+<CodeTab labels={["ReScript", "JS Output"]}>
7214+
7215+```res nocheck
7216+<MyComponent> child1 child2 </MyComponent>
7217+```
7218+
7219+```js
7220+import * as JsxRuntime from "react/jsx-runtime";
7221+
7222+JsxRuntime.jsxs(MyComponent, {
7223+ children: [child1, child2],
7224+});
7225+```
7226+
7227+</CodeTab>
7228+
7229+This is the syntax for passing a list of two items, `child1` and `child2`, to the children position. It transforms to a list containing `child1` and `child2`:
7230+
7231+<CodeTab labels={["ReScript", "JS Output"]}>
7232+
7233+```res nocheck
7234+React.jsxs(MyComponent.make, {children: React.array([child1, child2])})
7235+```
7236+
7237+```js
7238+import * as JsxRuntime from "react/jsx-runtime";
7239+
7240+JsxRuntime.jsxs(MyComponent, {
7241+ children: [child1, child2],
7242+});
7243+```
7244+
7245+</CodeTab>
7246+
7247+**Note** again that this isn't the transform for ReScriptReact; ReScriptReact turns the final list into an array. But the idea still applies.
7248+
7249+So naturally, `<MyComponent> myChild </MyComponent>` is transformed to `React.jsx(MyComponent.make, {children: myChild})`. I.e. whatever you do, the arguments passed to the children position will be wrapped in a list.
7250+
7251+## Usage
7252+
7253+See [ReScriptReact Elements & JSX](../react/elements-and-jsx.mdx) for an example application of JSX, which transforms the above calls into a ReScriptReact-specific call.
7254+
7255+Here's a JSX tag that shows most of the features.
7256+
7257+<CodeTab labels={["ReScript", "JS Output"]}>
7258+
7259+```res nocheck
7260+<MyComponent
7261+ booleanAttribute={true}
7262+ stringAttribute="string"
7263+ intAttribute=1
7264+ forcedOptional=?{Some("hello")}
7265+ onClick={handleClick}>
7266+ <div> {React.string("hello")} </div>
7267+</MyComponent>
7268+```
7269+
7270+```js
7271+import * as JsxRuntime from "react/jsx-runtime";
7272+
7273+JsxRuntime.jsx(Playground$MyComponent, {
7274+ children: JsxRuntime.jsx("div", {
7275+ children: "hello",
7276+ }),
7277+ booleanAttribute: true,
7278+ stringAttribute: "string",
7279+ intAttribute: 1,
7280+ forcedOptional: "hello",
7281+ onClick: handleClick,
7282+});
7283+```
7284+
7285+</CodeTab>
7286+
7287+## Departures From JS JSX
7288+
7289+- Attributes and children don't mandate `{}`, but we show them anyway for ease of learning. Once you format your file, some of them go away and some turn into parentheses.
7290+- Props spread is supported, but there are some restrictions (see below).
7291+- Punning!
7292+- Props and tag names have to follow ReScript's restrictions on identifiers at the exception of hyphens for lowercase tags ([see below](#hyphens-in-tag-names)).
7293+
7294+### Spread Props
7295+
7296+**Since 10.1**
7297+
7298+JSX props spread is supported with type safety.
7299+
7300+<CodeTab labels={["ReScript", "JS Output"]}>
7301+
7302+```res nocheck
7303+<Comp {...props} a="a" />
7304+```
7305+
7306+```js
7307+import * as JsxRuntime from "react/jsx-runtime";
7308+
7309+JsxRuntime.jsx(Comp.make, {
7310+ a: "a",
7311+ b: "b",
7312+});
7313+```
7314+
7315+</CodeTab>
7316+
7317+Multiple spreads are not allowed:
7318+
7319+<CodeTab labels={["ReScript"]}>
7320+
7321+```res nocheck
7322+<NotAllowed {...props1} {...props2} />
7323+```
7324+
7325+</CodeTab>
7326+
7327+The spread must be at the first position, followed by other props:
7328+
7329+<CodeTab labels={["ReScript"]}>
7330+
7331+```res nocheck
7332+<NotAllowed a="a" {...props} />
7333+```
7334+
7335+</CodeTab>
7336+
7337+### Punning
7338+
7339+"Punning" refers to the syntax shorthand for when a label and a value are the same. For example, in JavaScript, instead of doing `return {name: name}`, you can do `return {name}`.
7340+
7341+JSX supports punning. `<input checked />` is just a shorthand for `<input checked=checked />`. The formatter will help you format to the punned syntax whenever possible. This is convenient in the cases where there are lots of props to pass down:
7342+
7343+<CodeTab labels={["ReScript", "JS Output"]}>
7344+
7345+```res nocheck
7346+<MyComponent isLoading text onClick />
7347+```
7348+
7349+```js
7350+import * as JsxRuntime from "react/jsx-runtime";
7351+
7352+JsxRuntime.jsx(MyComponent, {
7353+ text: text,
7354+ isLoading: true,
7355+ onClick: onClick,
7356+});
7357+```
7358+
7359+</CodeTab>
7360+
7361+Consequently, a JSX component can cram in a few more props before reaching for extra libraries solutions that avoids props passing.
7362+
7363+**Note** that this is a departure from ReactJS JSX, which does **not** have punning. ReactJS' `<input checked />` desugars to `<input checked=true />`, in order to conform to DOM's idioms and for backward compatibility.
7364+
7365+### Hyphens in tag names
7366+
7367+**Since 11.1**
7368+
7369+JSX now supports lowercase tags with hyphens in their name. This allows to bind
7370+to web components.
7371+
7372+Note though that props names can't have hyphens, you should use `@as` to bind to
7373+such props in your custom `JsxDOM.domProps` type ([see generic JSX transform](#generic-jsx-transform-jsx-beyond-react-experimental)).
7374+
7375+<CodeTab labels={["ReScript", "JS Output"]}>
7376+
7377+```res nocheck
7378+<model-viewer src touchActions="pan-y"></model-viewer>
7379+```
7380+
7381+```js
7382+import * as JsxRuntime from "react/jsx-runtime";
7383+
7384+JsxRuntime.jsx("model-viewer", {
7385+ "touch-actions": "pan-y",
7386+ src: src,
7387+});
7388+```
7389+
7390+</CodeTab>
7391+
7392+## Generic JSX transform: JSX beyond React (experimental)
7393+
7394+**Since 11.1**
7395+
7396+While ReScript comes with first class support for JSX in React, it's also possible to have ReScript delegate JSX to other frameworks. You do that by configuring a _generic JSX transform_.
7397+
7398+This is what you need to do to use a generic JSX transform:
7399+
7400+1. Make sure you have a ReScript module that [implements the functions and types necessary for the JSX transform](#implementing-a-generic-jsx-transform-module).
7401+2. Configure `rescript.json` to delegated JSX to that module.
7402+
7403+That's it really. We'll expand on each point below.
7404+
7405+### Configuration
7406+
7407+You configure a generic JSX transform by putting any module name in the `module` config of JSX in `rescript.json`. This can be _any valid module name_. Example part from `rescript.json`:
7408+
7409+```json
7410+"jsx": {
7411+ "module": "Preact"
7412+ },
7413+```
7414+
7415+This will now put the `Preact` module in control of the generated JSX calls. The `Preact` module can be defined by anyone - locally in your project, or by a package. As long a it's available in the global scope. The JSX transform will delegate any JSX related code to `Preact`.
7416+
7417+#### What about `@react.component` for components?
7418+
7419+`@react.component` will still be available, and so is a generic `@jsx.component` notation. Both work the same way.
7420+
7421+### Usage Example
7422+
7423+Here's a quick usage example (the actual definition of `Preact.res` comes below):
7424+
7425+First, configure `rescript.json`:
7426+
7427+```json
7428+"jsx": {
7429+ "module": "Preact"
7430+ },
7431+```
7432+
7433+Now you can build Preact components:
7434+
7435+```rescript
7436+// Name.res
7437[email protected] // or @react.component if you want
7438+let make = (~name) => Preact.string(`Hello ${name}!`)
7439+```
7440+
7441+And you can use them just like normal with JSX:
7442+
7443+```rescript
7444+let name = <Name name="Test" />
7445+```
7446+
7447+#### File level configuration
7448+
7449+You can configure what JSX transform is used at the file level via `@@jsxConfig`, just like before. Like:
7450+
7451+```rescript
7452+@@jsxConfig({module_: "Preact"})
7453+```
7454+
7455+This can be convenient if you're mixing different JSX frameworks in the same project.
7456+
7457+### Implementing a generic JSX transform module
7458+
7459+Below is a full list of everything you need in a generic JSX transform module, including code comments to clarify. It's an example implementation of a `Preact` transform, so when doing this for other frameworks you'd of course adapt what you import from, and so on.
7460+
7461+> You can easily copy-paste-and-adapt this to your needs if you're creating bindings to a JSX framework. Most often, all you'll need to change is what the `@module("") external` points to, so the runtime calls point to the correct JS module.
7462+
7463+<CodeTab labels={["ReScript"]}>
7464+
7465+```rescript
7466+// Preact.res
7467+/* Below is a number of aliases to the common `Jsx` module */
7468+type element = Jsx.element
7469+
7470+type component<'props> = Jsx.component<'props>
7471+
7472+type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return>
7473+
7474+@module("preact/jsx-runtime")
7475+external jsx: (component<'props>, 'props) => element = "jsx"
7476+
7477+@module("preact/jsx-runtime")
7478+external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx"
7479+
7480+@module("preact/jsx-runtime")
7481+external jsxs: (component<'props>, 'props) => element = "jsxs"
7482+
7483+@module("preact/jsx-runtime")
7484+external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs"
7485+
7486+/* These identity functions and static values below are optional, but lets
7487+you move things easily to the `element` type. The only required thing to
7488+define though is `array`, which the JSX transform will output. */
7489+external array: array<element> => element = "%identity"
7490+@val external null: element = "null"
7491+
7492+external float: float => element = "%identity"
7493+external int: int => element = "%identity"
7494+external string: string => element = "%identity"
7495+external promise: promise<element> => element = "%identity"
7496+
7497+/* These are needed for Fragment (<> </>) support */
7498+type fragmentProps = {children?: element}
7499+
7500+@module("preact/jsx-runtime") external jsxFragment: component<fragmentProps> = "Fragment"
7501+
7502+/* The Elements module is the equivalent to the ReactDOM module in Preact. This holds things relevant to _lowercase_ JSX elements. */
7503+module Elements = {
7504+ /* Here you can control what props lowercase JSX elements should have.
7505+ A base that the React JSX transform uses is provided via JsxDOM.domProps,
7506+ but you can make this anything. The editor tooling will support
7507+ autocompletion etc for your specific type. */
7508+ type props = JsxDOM.domProps
7509+
7510+ @module("preact/jsx-runtime")
7511+ external jsx: (string, props) => Jsx.element = "jsx"
7512+
7513+ @module("preact/jsx-runtime")
7514+ external div: (string, props) => Jsx.element = "jsx"
7515+
7516+ @module("preact/jsx-runtime")
7517+ external jsxKeyed: (string, props, ~key: string=?, @ignore unit) => Jsx.element = "jsx"
7518+
7519+ @module("preact/jsx-runtime")
7520+ external jsxs: (string, props) => Jsx.element = "jsxs"
7521+
7522+ @module("preact/jsx-runtime")
7523+ external jsxsKeyed: (string, props, ~key: string=?, @ignore unit) => Jsx.element = "jsxs"
7524+
7525+ external someElement: element => option<element> = "%identity"
7526+}
7527+```
7528+
7529+</CodeTab>
7530+
7531+As you can see, most of the things you'll want to implement will be copy paste from the above. But do note that **everything needs to be there unless explicitly noted** or the transform will fail at compile time.
7532+
7533+To enable this, you need to configure the `jsx` `module` in your `rescript.json`:
7534+
7535+```json
7536+{
7537+ "jsx": {
7538+ "version": 4,
7539+ "module": "Preact"
7540+ }
7541+}
7542+```
7543+
7544+_value "Preact" is the name of the module that implements the generic JSX transform._
7545+
7546+## Preserve mode
7547+
7548+**Since 12.0**
7549+
7550+JSX Preserve Mode keeps JSX syntax in the compiled JavaScript output instead of transforming it to `JsxRuntime.jsx` calls. This lets bundlers (ESBuild, SWC, Next.js) or React Server Components handle JSX transformation.
7551+
7552+### Configuration
7553+
7554+```json
7555+{
7556+ "jsx": {
7557+ "version": 4,
7558+ "preserve": true
7559+ }
7560+}
7561+```
7562+
7563+<CodeTab labels={["ReScript", "JS Output"]}>
7564+
7565+```res nocheck
7566+let c1 = <div className="foo"> {React.string("Hello")} </div>
7567+let c2 = <MyComponent text="hey" isLoading=true onClick />
7568+```
7569+
7570+```js
7571+let c1 = <div className={"foo"}>{"Hello"}</div>;
7572+
7573+let c2 = <MyComponent.make text={"hey"} isLoading={true} onClick={onClick} />;
7574+```
7575+
7576+</CodeTab>
7577+
7578+Note that the JSX output is functional but not always the most aesthetically pleasing.
7579+
7580+---
7581+title: "Lazy Value"
7582+description: "Data type for deferred computation in ReScript"
7583+canonical: "/docs/manual/lazy-values"
7584+section: "Language Features"
7585+order: 20
7586+---
7587+
7588+# Lazy Value
7589+
7590+If you have some expensive computations you'd like to **defer and cache** subsequently, you can turn them into _lazy_ values:
7591+
7592+<CodeTab labels={["ReScript", "JS Output"]}>
7593+
7594+```res prelude
7595+@module("node:fs")
7596+external readdirSync: string => array<string> = "readdirSync"
7597+
7598+// Read the directory, only once
7599+let expensiveFilesRead = Lazy.make(() => {
7600+ Console.log("Reading dir")
7601+ readdirSync("./pages")
7602+})
7603+```
7604+
7605+```js
7606+import * as Lazy from "./stdlib/Lazy.js";
7607+import * as Nodefs from "node:fs";
7608+
7609+let expensiveFilesRead = Lazy.make(() => {
7610+ console.log("Reading dir");
7611+ return Nodefs.readdirSync("./pages");
7612+});
7613+```
7614+
7615+</CodeTab>
7616+
7617+**Note**: a lazy value is **not** a [shared data type](./shared-data-types.mdx). Don't rely on its runtime representation in your JavaScript code.
7618+
7619+## Execute The Lazy Computation
7620+
7621+To actually run the lazy value's computation, use `Lazy.get` from the standard library `Lazy` module:
7622+
7623+<CodeTab labels={["ReScript", "JS Output"]}>
7624+
7625+```res
7626+// First call. The computation happens
7627+Console.log(Lazy.get(expensiveFilesRead)) // logs "Reading dir" and the directory content
7628+
7629+// Second call. Will just return the already calculated result
7630+Console.log(Lazy.get(expensiveFilesRead)) // logs the directory content
7631+```
7632+
7633+```js
7634+import * as Nodefs from "node:fs";
7635+import * as Stdlib_Lazy from "@rescript/runtime/lib/es6/Stdlib_Lazy.js";
7636+
7637+let expensiveFilesRead = Stdlib_Lazy.make(() => {
7638+ console.log("Reading dir");
7639+ return Nodefs.readdirSync("./pages");
7640+});
7641+
7642+console.log(Stdlib_Lazy.get(expensiveFilesRead));
7643+
7644+console.log(Stdlib_Lazy.get(expensiveFilesRead));
7645+
7646+export { expensiveFilesRead };
7647+```
7648+
7649+</CodeTab>
7650+
7651+The first time `Lazy.get` is called, the expensive computation happens and the result is **cached**. The second time, the cached value is directly used.
7652+
7653+**You can't re-trigger the computation after the first `get` call**. Make sure you only use a lazy value with computations whose results don't change (e.g. an expensive server request whose response is always the same).
7654+
7655+## Exception Handling
7656+
7657+For completeness' sake, our files read example might throw an exception because of `readdirSync`. Here's how you'd handle it:
7658+
7659+<CodeTab labels={["ReScript", "JS Output"]}>
7660+
7661+```res
7662+let result = try {
7663+ Lazy.get(expensiveFilesRead)
7664+} catch {
7665+| Not_found => [] // empty array of files
7666+}
7667+```
7668+
7669+```js
7670+import * as Nodefs from "node:fs";
7671+import * as Stdlib_Lazy from "@rescript/runtime/lib/es6/Stdlib_Lazy.js";
7672+import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
7673+
7674+let expensiveFilesRead = Stdlib_Lazy.make(() => {
7675+ console.log("Reading dir");
7676+ return Nodefs.readdirSync("./pages");
7677+});
7678+
7679+let result;
7680+
7681+try {
7682+ result = Stdlib_Lazy.get(expensiveFilesRead);
7683+} catch (raw_exn) {
7684+ let exn = Primitive_exceptions.internalToException(raw_exn);
7685+ if (exn.RE_EXN_ID === "Not_found") {
7686+ result = [];
7687+ } else {
7688+ throw exn;
7689+ }
7690+}
7691+
7692+export { expensiveFilesRead, result };
7693+```
7694+
7695+</CodeTab>
7696+
7697+Though you should probably handle the exception inside the lazy computation itself.
7698+
7699+---
7700+title: "Let Binding"
7701+description: "Let binding syntax for binding to values in ReScript"
7702+canonical: "/docs/manual/let-binding"
7703+section: "Language Features"
7704+order: 2
7705+---
7706+
7707+# Let Binding
7708+
7709+A "let binding", in other languages, might be called a "variable declaration". `let` _binds_ values to names. They can be seen and referenced by code that comes _after_ them.
7710+
7711+<CodeTab labels={["ReScript", "JS Output"]}>
7712+
7713+```res
7714+let greeting = "hello!"
7715+let score = 10
7716+let newScore = 10 + score
7717+```
7718+
7719+```js
7720+let newScore = 20;
7721+
7722+let greeting = "hello!";
7723+
7724+let score = 10;
7725+
7726+export { greeting, score, newScore };
7727+```
7728+
7729+</CodeTab>
7730+
7731+Because these bindings are pure and known up front, the JS output can inline the calculation and emit `20` directly for `newScore`.
7732+
7733+## Block Scope
7734+
7735+Bindings can be scoped through `{}`.
7736+
7737+<CodeTab labels={["ReScript", "JS Output"]}>
7738+
7739+```res
7740+let message = {
7741+ let part1 = "hello"
7742+ let part2 = "world"
7743+ part1 ++ " " ++ part2
7744+}
7745+// `part1` and `part2` not accessible here!
7746+```
7747+
7748+```js
7749+let message = "hello world";
7750+
7751+export { message };
7752+```
7753+
7754+</CodeTab>
7755+
7756+The whole block is pure too, so the generated JS can collapse it to the final string literal.
7757+
7758+The value of the last line of a scope is implicitly returned.
7759+
7760+### Design Decisions
7761+
7762+ReScript's `if`, `while` and functions all use the same block scoping mechanism. The code below works **not** because of some special "if scope"; but simply because it's the same scope syntax and feature you just saw:
7763+
7764+<CodeTab labels={["ReScript", "JS Output"]}>
7765+
7766+```res nocheck
7767+if displayGreeting {
7768+ let message = "Enjoying the docs so far?"
7769+ Console.log(message)
7770+}
7771+// `message` not accessible here!
7772+```
7773+
7774+```js
7775+if (displayGreeting) {
7776+ console.log("Enjoying the docs so far?");
7777+}
7778+```
7779+
7780+</CodeTab>
7781+
7782+## Bindings Are Immutable
7783+
7784+Let bindings are "immutable", aka "cannot change". This helps our type system deduce and optimize much more than other languages (and in turn, help you more).
7785+
7786+## Binding Shadowing
7787+
7788+The above restriction might sound unpractical at first. How would you change a value then? Usually, 2 ways:
7789+
7790+The first is to realize that many times, what you want isn't to mutate a variable's value. For example, this JavaScript pattern:
7791+
7792+```js
7793+var result = 0;
7794+result = calculate(result);
7795+result = calculateSomeMore(result);
7796+```
7797+
7798+...is really just to comment on intermediate steps. You didn't need to mutate `result` at all! You could have just written this JS:
7799+
7800+```js
7801+var result1 = 0;
7802+var result2 = calculate(result1);
7803+var result3 = calculateSomeMore(result2);
7804+```
7805+
7806+In ReScript, this obviously works too:
7807+
7808+<CodeTab labels={["ReScript", "JS Output"]}>
7809+
7810+```res nocheck
7811+let result1 = 0
7812+let result2 = calculate(result1)
7813+let result3 = calculateSomeMore(result2)
7814+```
7815+
7816+```js
7817+var result1 = 0;
7818+var result2 = calculate(0);
7819+var result3 = calculateSomeMore(result2);
7820+```
7821+
7822+</CodeTab>
7823+
7824+Additionally, reusing the same let binding name overshadows the previous bindings with the same name. So you can write this too:
7825+
7826+<CodeTab labels={["ReScript", "JS Output"]}>
7827+
7828+```res nocheck
7829+let result = 0
7830+let result = calculate(result)
7831+let result = calculateSomeMore(result)
7832+```
7833+
7834+```js
7835+var result = calculate(0);
7836+var result$1 = calculateSomeMore(result);
7837+```
7838+
7839+</CodeTab>
7840+
7841+(Though for the sake of clarity, we don't recommend this).
7842+
7843+As a matter of fact, even this is valid code:
7844+
7845+<CodeTab labels={["ReScript", "JS Output"]}>
7846+
7847+```res
7848+let result = "hello"
7849+Console.log(result) // prints "hello"
7850+let result = 1
7851+Console.log(result) // prints 1
7852+```
7853+
7854+```js
7855+console.log("hello");
7856+
7857+console.log(1);
7858+
7859+let result = 1;
7860+
7861+export { result };
7862+```
7863+
7864+</CodeTab>
7865+
7866+The binding you refer to is whatever's the closest upward. No mutation here!
7867+If you need _real_ mutation, e.g. passing a value around, have it modified by many pieces of code, we provide a slightly heavier [mutation feature](./mutation.mdx).
7868+
7869+## Private let bindings
7870+
7871+Private let bindings are introduced in the release [7.2](../../blog/archived/bucklescript-release-7-2.mdx).
7872+
7873+In the module system, everything is public by default,
7874+the only way to hide some values is by providing a separate signature to
7875+list public fields and their types:
7876+
7877+```res
7878+module A: {
7879+ let b: int
7880+} = {
7881+ let a = 3
7882+ let b = 4
7883+}
7884+```
7885+
7886+`%%private` gives you an option to mark private fields directly
7887+
7888+```res
7889+module A = {
7890+ %%private(let a = 3)
7891+ let b = 4
7892+}
7893+```
7894+
7895+`%%private` also applies to file level modules, so in some cases,
7896+users do not need to provide a separate interface file just to hide some particular values.
7897+
7898+Note interface files are still recommended as a general best practice since they give you better
7899+separate compilation units and also they're better for documentation.
7900+
7901+Still, `%%private` is useful in the following scenarios:
7902+
7903+- **Code generators.** Some code generators want to hide some values but it is sometimes very hard or time consuming for code generators to synthesize the types for public fields.
7904+
7905+- **Quick prototyping.** During prototyping, we still want to hide some values, but the interface file is not stable yet. `%%private` provides you such convenience.
7906+
7907+---
7908+title: "Libraries & Publishing"
7909+description: "Install & publish ReScript packages"
7910+canonical: "/docs/manual/libraries"
7911+section: "JavaScript Interop"
7912+order: 14
7913+---
7914+
7915+# Libraries & Publishing
7916+
7917+ReScript libraries are just like JavaScript libraries: published & hosted on [NPM](http://npmjs.com). You can reuse your `npm`, `yarn` and `package.json`-related tools to manage them!
7918+
7919+## Tips & Tricks
7920+
7921+### Publish
7922+
7923+We recommend you to check in your compiled JavaScript output, for its [various benefits](./interop-with-js-build-systems.mdx#popular-js-build-systems). If not, then at least consider publishing the JavaScript output by un-ignoring them in your [npmignore](https://docs.npmjs.com/cli/v7/using-npm/developers#keeping-files-out-of-your-package). This way, your published ReScript package comes with plain JavaScript files that JS users can consume. If your project's good, JS users might not even realize that they've installed a library written in ReScript!
7924+
7925+### Find Libraries
7926+
7927+Search `rescript`-related packages on NPM, or use our [Package Index](/packages).
7928+
7929+If you can't find what you're looking for, remember that **you don't need a wrapper** to use a JS library:
7930+
7931+- Most JS data types, such as array and objects, [map over cleanly to ReScript and vice-versa](./shared-data-types.mdx).
7932+- You also have access to the familiar [Core API](/docs/manual/api/stdlib).
7933+- You can use a JavaScript library without needing to install dedicated binding libraries. Check the [`external`](./external.mdx) page.
7934+
7935+---
7936+title: "LLMs"
7937+description: "Documentation for LLMs"
7938+canonical: "/docs/manual/llms"
7939+section: "Overview"
7940+order: 4
7941+---
7942+
7943+# Documentation for LLMs
7944+
7945+We adhere to the [llms.txt convention](https://llmstxt.org/) to make documentation accessible to large language models and their applications.
7946+
7947+Currently, we have the following files...
7948+
7949+- [/llms/manual/llms.txt](/llms/manual/llms.txt) — a list of the available files for ReScript language.
7950+- [/llms/manual/llm-full.txt](/llms/manual/llm-full.txt) — complete documentation for ReScript language.
7951+- [/llms/manual/llm-small.txt](/llms/manual/llm-small.txt) — compressed version of the former, without examples.
7952+
7953+...and package-level documentation:
7954+
7955+- [/docs/react/llms](../react/llms.mdx) — the LLms documentation for ReScript React.
7956+
7957+## Notes
7958+
7959+- The content is automatically generated from the same source as the official documentation for the specific version
7960+
7961+---
7962+title: "Migrate to v11"
7963+description: "Instructions on upgrading to ReScript 11"
7964+canonical: "/docs/manual/migrate-to-v11"
7965+---
7966+
7967+# Migrate to ReScript 11
7968+
7969+## Foreword
7970+
7971+The ReScript community is proud to introduce ReScript V11 which comes with a ton of new features but also removes a lot of bulk.
7972+A migration to it can be very straightforward, but it can also take some time, depending on your code style or what dependencies you use.
7973+
7974+Please have a look at the full [set of breaking changes](#list-of-all-breaking-changes) below to be able to decide whether this is a task you want to undertake. There is also the possibilty to [opt-out of uncurried mode](#minimal-migration) for now, which is probably the most fundamental change of this release. That and other new and notable features are discussed in the following blogposts:
7975+
7976+- [Blog: Improving Interop with unboxed types](../../blog/improving-interop.mdx)
7977+- [Blog: Enhanced Ergonomics for Record Types](../../blog/enhanced-ergonomics-for-record-types.mdx)
7978+- [Blog: First-Class Dynamic `import()` Support](../../blog/first-class-dynamic-import-support.mdx)
7979+- [Blog: Uncurried Mode by Default](../../blog/uncurried-mode.mdx)
7980+
7981+## Recommended Migration
7982+
7983+### Uncurried Mode
7984+
7985+For uncurried mode to take effect in ReScript 11 there is nothing to configure, it is activated by default.
7986+
7987+### Adapt suffix
7988+
7989+ReScript 11 now allows having arbitrary suffixes in the generated JavaScript files. However, it is still recommended to stick to using `.res.js`, `.res.mjs` or `.res.cjs`. For more information, read the Build System Configuration about [suffixes](./build-configuration.mdx#suffix).
7990+
7991+### rescript.json
7992+
7993+The old configuration filename `bsconfig.json` is deprecated. Rename `bsconfig.json` to `rescript.json` to get rid of the deprecation warning.
7994+
7995+### ReScript Core standard library
7996+
7997+[ReScript Core](https://github.com/rescript-association/rescript-core) is ReScript's new standard library. It replaces the complete `Js` module as well as some of the more frequently used modules from `Belt` and is recommended to use with uncurried mode.
7998+
7999+It will be integrated into the compiler in a future version. In ReScript 11, it still needs to be installed manually:
8000+
8001+```console
8002+$ npm install @rescript/core
8003+```
8004+
8005+Then add `@rescript/core` to your `rescript.json`'s dependencies:
8006+
8007+```diff
8008+ {
8009+ "bs-dependencies": [
8010++ "@rescript/core"
8011+ ]
8012+ }
8013+```
8014+
8015+Open it so it's available in the global scope.
8016+
8017+```diff
8018+ {
8019+ "bsc-flags": [
8020++ "-open RescriptCore",
8021+ ]
8022+ }
8023+```
8024+
8025+One major change to be aware of is that array access now returns an `option`.
8026+
8027+```res nocheck
8028+let firstItem = myArray[0] // Some("hello")
8029+```
8030+
8031+If you would like to not use an `option`, you can use [`Array.getUnsafe`](/docs/manual/api/stdlib/array#value-getUnsafe).
8032+
8033+For a detailed explanation on migration to ReScript Core, please refer to its [migration guide](https://github.com/rescript-association/rescript-core#migration). A semi-automated script is available as well.
8034+
8035+See ReScript Core API docs [here](/docs/manual/api/stdlib).
8036+
8037+### Removed bindings
8038+
8039+Many Node bindings have been removed from the compiler. Please use [rescript-nodejs](https://github.com/TheSpyder/rescript-nodejs) instead or write your own local bindings.
8040+
8041+## Minimal Migration
8042+
8043+This guide describes the things to do at least to migrate to ReScript 11.
8044+
8045+### Disable uncurried mode
8046+
8047+If you use currying extensively and don't want to bother with adapting your code, or have dependencies that just don't work with uncurried mode yet, just set it to false in your `rescript.json`.
8048+
8049+```json
8050+{
8051+ "uncurried": false
8052+}
8053+```
8054+
8055+For more information, read the Build System Configuration about [uncurried](./build-configuration.mdx#uncurried).
8056+
8057+## List of all breaking changes
8058+
8059+Below is an excerpt from the compiler changelog about all the breaking changes of ReScript 11.
8060+
8061+### Language and Compiler
8062+
8063+- Add smart printer for pipe chains. https://github.com/rescript-lang/rescript-compiler/pull/6411 (the formatter will reformat existing code in certain cases)
8064+- Parse `assert` as a regular function. `assert` is no longer a unary expression. Example: before `assert 1 == 2` is parsed as `(assert 1) == 2`, now it is parsed as `assert(1 == 2)`. https://github.com/rescript-lang/rescript-compiler/pull/6180
8065+- Remove support for the legacy Reason syntax. Existing Reason code can be converted to ReScript syntax using ReScript 9 as follows:
8066+ - `npx rescript@9 convert <reason files>`
8067+- Curried after uncurried is not fused anymore: `(. x) => y => 3` is not equivalent to `(. x, y) => 3` anymore. It's instead equivalent to `(. x) => { y => 3 }`.
8068+ Also, `(. int) => string => bool` is not equivalen to `(. int, string) => bool` anymore.
8069+ These are only breaking changes for unformatted code.
8070+- Exponentiation operator `**` is now right-associative. `2. ** 3. ** 2.` now compile to `Math.pow(2, Math.pow(3, 2))` and not anymore `Math.pow(Math.pow(2, 3), 2)`. Parentheses can be used to change precedence.
8071+- Stop mangling object field names. If you had objects with field names containing "\_\_" or leading "\_", they won't be mangled in the compiled JavaScript and represented as it is without changes. https://github.com/rescript-lang/rescript-compiler/pull/6354
8072+- `$$default` is no longer exported from the generated JavaScript when using default exports. https://github.com/rescript-lang/rescript-compiler/pull/6328
8073+- `-bs-super-errors` flag has been deprecated along with Super_errors. https://github.com/rescript-lang/rescript-compiler/pull/6243
8074+- Remove unsafe `` j`$(a)$(b)` `` interpolation deprecated in compiler version 10 https://github.com/rescript-lang/rescript-compiler/pull/6068
8075+- `@deriving(jsConverter)` not supported anymore for variant types https://github.com/rescript-lang/rescript-compiler/pull/6088
8076+- New representation for variants, where the tag is a string instead of a number. https://github.com/rescript-lang/rescript-compiler/pull/6088
8077+
8078+### Compiler Libraries
8079+
8080+- Fixed name collision between the newly defined Js.Json.t and the variant constructor in the existing Js.Json.kind type. To address this, the usage of the existing Js.Json.kind type can be updated to Js.Json.Kind.t. https://github.com/rescript-lang/rescript-compiler/pull/6317
8081+- Remove rudimentary node bindings and undocumented `%node` extension. https://github.com/rescript-lang/rescript-compiler/pull/6285
8082+- `@rescript/react` >= 0.12.0-alpha.2 is now required because of the React.fragment's children type fix. https://github.com/rescript-lang/rescript-compiler/pull/6238
8083+- Remove deprecated module `Printexc`
8084+
8085+### Build System and Tools
8086+
8087+- Update watcher rules to recompile only on config and `*.res`/`*.resi`/`*.ml`/`.mli` file changes. Solves the issue of unnecessary recompiles on `.css`, `.ts`, and other unrelated file changes. https://github.com/rescript-lang/rescript-compiler/pull/6420
8088+- Made pinned dependencies transitive: if _a_ is a pinned dependency of _b_ and _b_ is a pinned dependency of _c_, then _a_ is implicitly a pinned dependency of _c_. This change is only breaking if your build process assumes non-transitivity.
8089+- Remove obsolete built-in project templates and the "rescript init" functionality. This is replaced by [create-rescript-app](https://github.com/rescript-lang/create-rescript-app) which is maintained separately.
8090+- Do not attempt to build ReScript from source on npm postinstall for platforms without prebuilt binaries anymore.
8091+- GenType: removed support for `@genType.as` for records and variants which has become unnecessary. Use the language's `@as` instead to channge the runtime representation without requiring any runtime conversion during FFI. https://github.com/rescript-lang/rescript-compiler/pull/6099 https://github.com/rescript-lang/rescript-compiler/pull/6101
8092+
8093+---
8094+title: "Migrate to v12"
8095+description: "Instructions on upgrading to ReScript 12"
8096+canonical: "/docs/manual/migrate-to-v12"
8097+section: "Overview"
8098+order: 5
8099+---
8100+
8101+# Migrate to ReScript 12
8102+
8103+If you encounter any missing information or issues during migration, please [open an issue](https://github.com/rescript-lang/rescript-lang.org/issues/new?template=documentation_issue.md) or, even better, [send a pull request](https://github.com/rescript-lang/rescript-lang.org/) to help improve this guide.
8104+
8105+## Recommended Migration
8106+
8107+### Prerequisites
8108+
8109+- ReScript V11 project.
8110+- Uncurried mode must be enabled (i.e. you have not opted-out from it).
8111+- Your project must not contain any OCaml source code anymore, as support for `.ml` files is removed in this version. However there are ways to convert OCaml syntax with an older ReScript compiler version ([see below](#converting-generated-ml-files)).
8112+- Minimum supported Node.js version is 20.11.0.
8113+
8114+### Standard Library Changes
8115+
8116+In V12, the new standard library ships with the compiler, so you can uninstall and remove the `@rescript/core` dependency from your `rescript.json`
8117+
8118+```console
8119+$ npm remove @rescript/core
8120+```
8121+
8122+```diff
8123+ {
8124+ "bs-dependencies": [
8125+- "@rescript/core"
8126+ ]
8127+ }
8128+```
8129+
8130+Also remove auto opening of `RescriptCore`.
8131+
8132+```diff
8133+ {
8134+ "bsc-flags": [
8135+- "-open RescriptCore",
8136+ ]
8137+ }
8138+```
8139+
8140+if you had `@rescript/std` installed, remove it as well:
8141+
8142+```shell
8143+npm uninstall @rescript/std
8144+```
8145+
8146+this is replaced by `@rescript/runtime`, which is installed as a dependency of `rescript` now.
8147+
8148+<Info>
8149+ **pnpm users:** since pnpm does not hoist transitive dependencies, you may need to install `@rescript/runtime` as a direct dependency (`pnpm add @rescript/runtime`), or hoist it by adding the following to `pnpm-workspace.yaml`:
8150+
8151+```yaml
8152+publicHoistPattern:
8153+ - "*@rescript/runtime*"
8154+```
8155+
8156+</Info>
8157+
8158+## Replacements
8159+
8160+Some typical name changes include:
8161+
8162+- `Error.t` -> `JsError.t`
8163+- `raise(MyException("error"))` -> `throw(MyException("error"))`
8164+- `Js.Exn.Error` exception -> `JsExn`
8165+- `Error.make` -> `JsExn.make`
8166+- `Error.raise` -> `JsExn.raise`
8167+- `Error.message` -> `JsExn.message`
8168+- `Bool.fromStringExn("true")` -> `Bool.fromStringOrThrow("true")`
8169+- `Int.Bitwise.lsl` -> `Int.shiftLeft`
8170+
8171+Tip: You can use the migration tool to automatically replace these with the new functions.
8172+
8173+```shell
8174+npx rescript-tools migrate-all <root>
8175+
8176+# preview the changes via
8177+rescript-tools migrate <file> [--stdout]
8178+```
8179+
8180+### Bitwise operations
8181+
8182+v11:
8183+
8184+```res nocheck
8185+let w = lnot(a) // bitwise NOT
8186+let x = lxor(a, b) // bitwise XOR
8187+let y = land(a, b) // bitwise AND
8188+let z = lor(a, b) // bitwise OR
8189+```
8190+
8191+v12:
8192+
8193+```res nocheck
8194+let w = ~~~a // bitwise NOT
8195+let x = a ^^^ b // bitwise XOR
8196+let y = a &&& b // bitwise AND
8197+let z = a ||| b // bitwise OR
8198+```
8199+
8200+### Shift operations
8201+
8202+v11:
8203+
8204+```res nocheck
8205+let x = lsl(a, b) // logical left shift
8206+let y = lsr(a, b) // logical right shift
8207+let z = asr(a, b) // unsigned right shift
8208+```
8209+
8210+v12:
8211+
8212+```res nocheck
8213+let x = a << b // logical left shift
8214+let y = a >> b // logical right shift
8215+let z = a >>> b // unsigned right shift
8216+```
8217+
8218+### JSX children spread
8219+
8220+v11:
8221+
8222+```res nocheck
8223+<div> ...children </div>
8224+```
8225+
8226+v12:
8227+
8228+```res nocheck
8229+<div> children </div>
8230+```
8231+
8232+### Attributes
8233+
8234+v11:
8235+
8236+```res nocheck
8237[email protected]("foo")
8238[email protected]
8239[email protected]
8240+@raises
8241[email protected]
8242+```
8243+
8244+v12:
8245+
8246+```res nocheck
8247+@as("foo")
8248+@send
8249+@new
8250+@throws
8251+@as
8252+```
8253+
8254+- `@meth` and `@bs.send.pipe` are removed.
8255+
8256+### Assert
8257+
8258+v11:
8259+
8260+```res nocheck
8261+assert 1 == 2
8262+```
8263+
8264+v12:
8265+
8266+```res nocheck
8267+assert(1 == 2) // Now a regular function call
8268+```
8269+
8270+## Configuration
8271+
8272+Rename `bsconfig.json` to `rescript.json` and update these configuration options:
8273+
8274+- `bs-dependencies` → `dependencies`
8275+- `bs-dev-dependencies` → `dev-dependencies`
8276+- `bsc-flags` → `compiler-flags`
8277+
8278+### jsx
8279+
8280+- Set `version` to `4` (lower versions are not supported)
8281+- Remove `mode` option (automatically set to `automatic`)
8282+
8283+## Build System Changes
8284+
8285+The build system has been completely rewritten in v12.0.0.
8286+
8287+In v11, we had:
8288+
8289+```shell
8290+# build
8291+rescript build
8292+
8293+# watch build
8294+rescript build -w
8295+
8296+# format
8297+rescript format -all
8298+```
8299+
8300+in v12, this becomes:
8301+
8302+```shell
8303+# build
8304+rescript
8305+
8306+# watch build
8307+rescript watch
8308+
8309+# format
8310+rescript format
8311+```
8312+
8313+## Converting generated `.ml` files
8314+
8315+**Note**: This setup is an escape hatch. It keeps legacy generators like `atdgen` working but it also forces you to maintain two compiler versions. Whenever possible migrate such things to modern ReScript tooling such as [Sury](https://github.com/DZakh/sury/).
8316+
8317+Some projects still rely on tools such as `atdgen` that emit `.ml` files. ReScript 12 cannot compile those files directly, so you must keep using ReScript 11 **only** to convert the generated `.ml` files back to `.res` files before you run the v12 build.
8318+
8319+1. Keep ReScript 12 as the sole compiler dependency in your main project (i.e. `devDependencies.rescript` stays at `^12.0.0`).
8320+
8321+2. Install ReScript 11 in a dedicated subfolder (so its binaries never replace the v12 ones in `node_modules/.bin`). A simple option is to store it under a subfolder, e.g. `tools` (if you're using workspaces, keep this folder out of the root workspace list so hoisting can't swap the v12 shims):
8322+
8323+`cd` into `tools` and run `npm create rescript-app` and select the basic template and a v11 version of ReScript. You can name it `rescript-11` for instance.
8324+
8325+3. `cd` back into the root of your project and add a helper script that references the compiler from that folder (adapt the path accordingly):
8326+
8327+ ```json
8328+ {
8329+ "scripts": {
8330+ "convert-ml": "tools/rescript-11/node_modules/.bin/rescript convert src/*.ml"
8331+ }
8332+ }
8333+ ```
8334+
8335+4. Execute the helper script to convert your `.ml` files to `.res` files:
8336+
8337+```console
8338+npm run convert-ml
8339+```
8340+
8341+## List of all breaking changes
8342+
8343+Below is a consolidated excerpt of all the breaking changes from the compiler changelog.
8344+
8345+### Language & syntax
8346+
8347+- Tag functions named `j` or `js` are no longer reserved, so add your own implementation whenever a tagged template expects them. https://github.com/rescript-lang/rescript-compiler/pull/6817
8348+- `lazy` syntax was removed; use the `Lazy` module instead. https://github.com/rescript-lang/rescript-compiler/pull/6342
8349+- All legacy `@bs.*` attributes (e.g. `@bs.as`, `@bs.send`) and `@bs.open` were removed; use their prefix-free successors (`@as`, `@send`, `@open`, …). https://github.com/rescript-lang/rescript-compiler/pull/6643 https://github.com/rescript-lang/rescript-compiler/pull/6629
8350+- `@bs.send.pipe` was removed; rewrite bindings to use `@send`. https://github.com/rescript-lang/rescript-compiler/pull/6858 https://github.com/rescript-lang/rescript-compiler/pull/6891
8351+- OCaml `.ml` files are no longer supported anywhere: `.ml` parsing/formatting went away and the `rescript convert` CLI was removed, so convert legacy files to `.res` before upgrading. https://github.com/rescript-lang/rescript-compiler/pull/6848 https://github.com/rescript-lang/rescript-compiler/pull/6852 https://github.com/rescript-lang/rescript-compiler/pull/6860
8352+- Some global names and old keywords are no longer automatically prefixed during JS emission; update any code that was relying on the mangled names. https://github.com/rescript-lang/rescript-compiler/pull/6831
8353+- JSX v3 and the `-bs-jsx-mode` option were removed and JSX children spreads are no longer valid; JSX v4 semantics are now the only supported mode. https://github.com/rescript-lang/rescript-compiler/pull/7072 https://github.com/rescript-lang/rescript/pull/7327 https://github.com/rescript-lang/rescript/pull/7869
8354+
8355+### Standard library & runtime
8356+
8357+- OCaml compatibility layers in the stdlib and primitives were removed/deprecated. https://github.com/rescript-lang/rescript-compiler/pull/6984
8358+- Deprecated modules `Js.Vector` and `Js.List` were deleted. https://github.com/rescript-lang/rescript-compiler/pull/6900
8359+- The legacy `js_cast.res` helpers were removed; migrate to explicit externals. https://github.com/rescript-lang/rescript-compiler/pull/7075
8360+- `JsError` and related modules were renamed/cleaned up under `JsExn`. https://github.com/rescript-lang/rescript/pull/7408
8361+- `BigInt.fromFloat` now returns `option` and exposes `BigInt.fromFloatOrThrow`, and the `Exn`-suffixed helpers across `Bool`, `BigInt`, `JSON`, `Option`, `Null`, `Nullable`, `Result`, and `List` now end with `OrThrow`. https://github.com/rescript-lang/rescript/pull/7419 https://github.com/rescript-lang/rescript/pull/7518 https://github.com/rescript-lang/rescript/pull/7554
8362+- `Result.getOrThrow` throws a JS `Error` (instead of `Not_found`), and `Result.equal` / `Result.compare` now provide a comparison function for `Error` values. https://github.com/rescript-lang/rescript/pull/7630 https://github.com/rescript-lang/rescript/pull/7933
8363+- `Iterator.forEach` now emits `Iterator.prototype.forEach`. https://github.com/rescript-lang/rescript/pull/7506
8364+- `Date.make` uses `~day` instead of `~date`. https://github.com/rescript-lang/rescript/pull/7324
8365+- Plain `int` multiplication is implemented as a regular int32 operation instead of `Math.imul`. https://github.com/rescript-lang/rescript/pull/7358
8366+- The `List` API was cleaned up—several functions were renamed or removed (see the PR for the exact surface). https://github.com/rescript-lang/rescript/pull/7290
8367+- `String.getSymbol` / `String.setSymbol` were removed; only `String.getSymbolUnsafe` remains on strings. https://github.com/rescript-lang/rescript/pull/7571 https://github.com/rescript-lang/rescript/pull/7626
8368+- `String.charCodeAt` now returns `option<int>` and exposes `String.charCodeAtUnsafe` for unchecked access. https://github.com/rescript-lang/rescript/pull/7877
8369+- `Intl.*.supportedLocalesOf` bindings now return `array<string>` and the non-portable `Intl.PluralRules.selectBigInt` / `selectRangeBigInt` were removed. https://github.com/rescript-lang/rescript/pull/7995
8370+
8371+### Build system & CLI
8372+
8373+- The new Rust-based `rewatch` build system now powers the `rescript` command. The old Ninja-based builder system moved behind `rescript legacy`, and `--compiler-args` became the `compiler-args` subcommand. https://github.com/rescript-lang/rescript/pull/7551 https://github.com/rescript-lang/rescript/pull/7593 https://github.com/rescript-lang/rescript/pull/7928
8374+- `rescript format` was reimplemented in Rust, its options now use the `--check` / `--stdin` long-form spelling, and the `--all` flag was removed because every tracked file (non-dev by default) is formatted automatically. https://github.com/rescript-lang/rescript/pull/7603 https://github.com/rescript-lang/rescript/pull/7752
8375+- The `rescript dump` command was removed; call `bsc` directly if you need to inspect `.cmi` files. https://github.com/rescript-lang/rescript/pull/7710
8376+
8377+### Configuration & platform
8378+
8379+- The minimum supported Node.js version is now 20.11.0. https://github.com/rescript-lang/rescript/pull/7354
8380+- The `experimental-features` key in `rescript.json` now uses kebab-case to match the other config fields. https://github.com/rescript-lang/rescript/pull/7891
8381+- The legacy `-bs-super-errors` flag was removed. https://github.com/rescript-lang/rescript-compiler/pull/6814
8382+
8383+---
8384+title: "Module Functions"
8385+description: "Module Functions in ReScript"
8386+canonical: "/docs/manual/module-functions"
8387+section: "Advanced Features"
8388+order: 3
8389+---
8390+
8391+# Module Functions
8392+
8393+Module functions can be used to create modules based on types, values, or functions from other modules.
8394+This is a powerful tool that can be used to create abstractions and reusable code that might not be possible with functions, or might have a runtime cost if done with functions.
8395+
8396+This is an advanced part of ReScript and you can generally get by with normal values and functions.
8397+
8398+## Quick example
8399+
8400+Next.js has a `useParams` hook that returns an unknown type,
8401+and it's up to the developer in TypeScript to add a type annotation for the parameters returned by the hook.
8402+
8403+```TS
8404+const params = useParams<{ tag: string; item: string }>()
8405+```
8406+
8407+In ReScript we can create a module function that will return a typed response for the `useParams` hook.
8408+
8409+<CodeTab labels={["ReScript", "JS Output"]}>
8410+```res
8411+module Next = {
8412+ // define our module function
8413+ module MakeParams = (Params: { type t }) => {
8414+ @module("next/navigation")
8415+ external useParams: unit => Params.t = "useParams"
8416+ /* You can use values from the function parameter, such as Params.t */
8417+ }
8418+}
8419+
8420+module Component: {
8421[email protected]
8422+let make: unit => Jsx.element
8423+} = {
8424+// Create a module that matches the module type expected by Next.MakeParams
8425+module P = {
8426+type t = {
8427+tag: string,
8428+item: string,
8429+}
8430+}
8431+
8432+// Create a new module using the Params module we created and the Next.MakeParams module function
8433+module Params = Next.MakeParams(P)
8434+
8435[email protected]
8436+let make = () => {
8437+
8438+// Use the functions, values, or types created by the module function
8439+let params = Params.useParams()
8440+
8441+ <div>
8442+ <p>
8443+ {React.string("Tag: " ++ params.tag /* params is fully typed! */)}
8444+ </p>
8445+ <p> {React.string("Item: " ++ params.item)} </p>
8446+ </div>
8447+ }
8448+}
8449+
8450+````
8451+```js
8452+import * as Navigation from "next/navigation";
8453+import * as JsxRuntime from "react/jsx-runtime";
8454+
8455+function MakeParams(Params) {
8456+ return {};
8457+}
8458+
8459+let Next = {
8460+ MakeParams: MakeParams
8461+};
8462+
8463+function _tempFile$Component(props) {
8464+ let params = Navigation.useParams();
8465+ return JsxRuntime.jsxs("div", {
8466+ children: [
8467+ JsxRuntime.jsx("p", {
8468+ children: "Tag: " + params.tag
8469+ }),
8470+ JsxRuntime.jsx("p", {
8471+ children: "Item: " + params.item
8472+ })
8473+ ]
8474+ });
8475+}
8476+
8477+let Component = {
8478+ make: _tempFile$Component
8479+};
8480+
8481+export {
8482+ Next,
8483+ Component,
8484+}
8485+````
8486+
8487+</ CodeTab>
8488+
8489+## Sharing a type with an external binding
8490+
8491+This becomes incredibly useful when you need to have types that are unique to a project but shared across multiple components.
8492+Let's say you want to create a library with a `getEnv` function to load in environment variables found in `import.meta.env`.
8493+
8494+```res
8495+@val external env: 'a = "import.meta.env"
8496+
8497+let getEnv = () => {
8498+ env
8499+}
8500+```
8501+
8502+It's not possible to define types for this that will work for every project, so we just set it as 'a and the consumer of our library can define the return type.
8503+
8504+```res nocheck
8505+type t = {"LOG_LEVEL": string}
8506+
8507+let values: t = getEnv()
8508+```
8509+
8510+This isn't great and it doesn't take advantage of ReScript's type system and ability to use types without type definitions, and it can't be easily shared across our application.
8511+
8512+We can instead create a module function that can return a module that has contains a `getEnv` function that has a typed response.
8513+
8514+```res
8515+module MakeEnv = (
8516+ E: {
8517+ type t
8518+ },
8519+) => {
8520+ @val external env: E.t = "import.meta.env"
8521+
8522+ let getEnv = () => {
8523+ env
8524+ }
8525+}
8526+```
8527+
8528+And now consumers of our library can define the types and create a custom version of the hook for their application.
8529+Notice that in the JavaScript output that the `import.meta.env` is used directly and doesn't require any function calls or runtime overhead.
8530+
8531+<CodeTab labels={["ReScript", "JS Output"]}>
8532+```res nocheck
8533+module Env = MakeEnv({
8534+ type t = {"LOG_LEVEL": string}
8535+})
8536+
8537+let values = Env.getEnv()
8538+
8539+````
8540+```js
8541+var Env = {
8542+ getEnv: getEnv
8543+};
8544+
8545+var values = import.meta.env;
8546+````
8547+
8548+</ CodeTab>
8549+
8550+## Shared functions
8551+
8552+You might want to share functions across modules, like a way to log a value or render it in React.
8553+Here's an example of module function that takes in a type and a transform to string function.
8554+
8555+```res
8556+module MakeDataModule = (
8557+ T: {
8558+ type t
8559+ let toString: t => string
8560+ },
8561+) => {
8562+ type t = T.t
8563+ let log = a => Console.log("The value is " ++ T.toString(a))
8564+
8565+ module Render = {
8566+ @react.component
8567+ let make = (~value) => value->T.toString->React.string
8568+ }
8569+}
8570+```
8571+
8572+You can now take a module with a type of `t` and a `toString` function and create a new module that has the `log` function and the `Render` component.
8573+
8574+<CodeTab labels={["ReScript", "JS Output"]}>
8575+```res nocheck
8576+module Person = {
8577+ type t = { firstName: string, lastName: string }
8578+ let toString = person => person.firstName ++ person.lastName
8579+}
8580+
8581+module PersonData = MakeDataModule(Person)
8582+
8583+````
8584+
8585+```js
8586+// Notice that none of the JS output references the MakeDataModule function
8587+
8588+function toString(person) {
8589+ return person.firstName + person.lastName;
8590+}
8591+
8592+var Person = {
8593+ toString: toString
8594+};
8595+
8596+function log(a) {
8597+ console.log("The value is " + toString(a));
8598+}
8599+
8600+function Person$MakeDataModule$Render(props) {
8601+ return toString(props.value);
8602+}
8603+
8604+var Render = {
8605+ make: Person$MakeDataModule$Render
8606+};
8607+
8608+var PersonData = {
8609+ log: log,
8610+ Render: Render
8611+};
8612+````
8613+
8614+</CodeTab>
8615+
8616+Now the `PersonData` module has the functions from the `MakeDataModule`.
8617+
8618+<CodeTab labels={["ReScript", "JS Output"]}>
8619+```res nocheck
8620[email protected]
8621+let make = (~person) => {
8622+ let handleClick = _ => PersonData.log(person)
8623+ <div>
8624+ {React.string("Hello ")}
8625+ <PersonData.Render value=person />
8626+ <button onClick=handleClick>
8627+ {React.string("Log value to console")}
8628+ </button>
8629+ </div>
8630+}
8631+```
8632+```js
8633+function Person$1(props) {
8634+ var person = props.person;
8635+ var handleClick = function (param) {
8636+ log(person);
8637+ };
8638+ return JsxRuntime.jsxs("div", {
8639+ children: [
8640+ "Hello ",
8641+ JsxRuntime.jsx(Person$MakeDataModule$Render, {
8642+ value: person
8643+ }),
8644+ JsxRuntime.jsx("button", {
8645+ children: "Log value to console",
8646+ onClick: handleClick
8647+ })
8648+ ]
8649+ });
8650+}
8651+```
8652+</CodeTab>
8653+
8654+## Dependency injection
8655+
8656+Module functions can be used for dependency injection.
8657+Here's an example of injecting in some config values into a set of functions to access a database.
8658+
8659+<CodeTab labels={["ReScript", "JS Output"]}>
8660+```res
8661+module type DbConfig = {
8662+ let host: string
8663+ let database: string
8664+ let username: string
8665+ let password: string
8666+}
8667+
8668+module MakeDbConnection = (Config: DbConfig) => {
8669+type client = {
8670+write: string => unit,
8671+read: string => string,
8672+}
8673+@module("database.js")
8674+external makeClient: (string, string, string, string) => client = "makeClient"
8675+
8676+let client = makeClient(Config.host, Config.database, Config.username, Config.password)
8677+}
8678+
8679+module Db = MakeDbConnection({
8680+let host = "localhost"
8681+let database = "mydb"
8682+let username = "root"
8683+let password = "password"
8684+})
8685+
8686+let updateDb = Db.client.write("new value")
8687+
8688+````
8689+```js
8690+import * as DatabaseJs from "database.js";
8691+
8692+function MakeDbConnection(Config) {
8693+ let client = DatabaseJs.makeClient(Config.host, Config.database, Config.username, Config.password);
8694+ return {
8695+ client: client
8696+ };
8697+}
8698+
8699+let client = DatabaseJs.makeClient("localhost", "mydb", "root", "password");
8700+
8701+let Db = {
8702+ client: client
8703+};
8704+
8705+let updateDb = client.write("new value");
8706+
8707+export {
8708+ MakeDbConnection,
8709+ Db,
8710+ updateDb,
8711+}
8712+````
8713+
8714+</CodeTab>
8715+
8716+---
8717+title: "Module"
8718+description: "ReScript modules, module signatures and interface files"
8719+canonical: "/docs/manual/module"
8720+section: "Language Features"
8721+order: 24
8722+---
8723+
8724+# Module
8725+
8726+## Basics
8727+
8728+**Modules are like mini files**! They can contain type definitions, `let`
8729+bindings, nested modules, etc.
8730+
8731+### Creation
8732+
8733+To create a module, use the `module` keyword. The module name must start with a
8734+**capital letter**. Whatever you could place in a `.res` file, you may place
8735+inside a module definition's `{}` block.
8736+
8737+<CodeTab labels={["ReScript", "JS Output"]}>
8738+
8739+```res nocheck
8740+module School = {
8741+ type profession = Teacher | Director
8742+
8743+ let person1 = Teacher
8744+ let getProfession = (person) =>
8745+ switch person {
8746+ | Teacher => "A teacher"
8747+ | Director => "A director"
8748+ }
8749+}
8750+```
8751+
8752+```js
8753+function getProfession(person) {
8754+ if (person === "Teacher") {
8755+ return "A teacher";
8756+ } else {
8757+ return "A director";
8758+ }
8759+}
8760+
8761+let School = {
8762+ person1: "Teacher",
8763+ getProfession: getProfession,
8764+};
8765+
8766+export { School };
8767+```
8768+
8769+</CodeTab>
8770+
8771+A module's contents (including types!) can be accessed much like a record's,
8772+using the `.` notation. This demonstrates modules' utility for namespacing.
8773+
8774+<CodeTab labels={["ReScript", "JS Output"]}>
8775+
8776+```res nocheck
8777+let anotherPerson: School.profession = School.Teacher
8778+Console.log(School.getProfession(anotherPerson)) /* "A teacher" */
8779+```
8780+
8781+```js
8782+var anotherPerson = /* Teacher */ 0;
8783+console.log("A teacher");
8784+```
8785+
8786+</CodeTab>
8787+
8788+Nested modules work too.
8789+
8790+<CodeTab labels={["ReScript", "JS Output"]}>
8791+
8792+```res nocheck
8793+module MyModule = {
8794+ module NestedModule = {
8795+ let message = "hello"
8796+ }
8797+}
8798+
8799+let message = MyModule.NestedModule.message
8800+```
8801+
8802+```js
8803+let message = "hello";
8804+
8805+let NestedModule = {
8806+ message: message,
8807+};
8808+
8809+let MyModule = {
8810+ NestedModule: NestedModule,
8811+};
8812+
8813+export { MyModule, message };
8814+```
8815+
8816+</CodeTab>
8817+
8818+### `open`ing a module
8819+
8820+Constantly referring to a value/type in a module can be tedious. Instead, we can "open" a module and refer to its contents without always prepending them with the
8821+module's name. Instead of writing:
8822+
8823+<CodeTab labels={["ReScript", "JS Output"]}>
8824+
8825+```res nocheck
8826+let p = School.getProfession(School.person1)
8827+```
8828+
8829+```js
8830+var p = School.getProfession(School.person1);
8831+```
8832+
8833+</CodeTab>
8834+
8835+We can write:
8836+
8837+<CodeTab labels={["ReScript", "JS Output"]}>
8838+
8839+```res nocheck
8840+open School
8841+let p = getProfession(person1)
8842+```
8843+
8844+```js
8845+var p = School.getProfession(School.person1);
8846+```
8847+
8848+</CodeTab>
8849+
8850+The content of `School` module are made visible (**not** copied into the file, but simply made visible!) in scope. `profession`, `getProfession` and `person1` will thus correctly be found.
8851+
8852+**Use `open` this sparingly, it's convenient, but makes it hard to know where some values come from**. You should usually use `open` in a local scope:
8853+
8854+<CodeTab labels={["ReScript", "JS Output"]}>
8855+
8856+```res nocheck
8857+let p = {
8858+ open School
8859+ getProfession(person1)
8860+}
8861+/* School's content isn't visible here anymore */
8862+```
8863+
8864+```js
8865+var p = School.getProfession(School.person1);
8866+```
8867+
8868+</CodeTab>
8869+
8870+### Use `open!` to ignore shadow warnings
8871+
8872+There are situations where `open` will cause a warning due to existing identifiers (bindings, types) being redefined. Use `open!` to explicitly tell the compiler that this is desired behavior.
8873+
8874+```res nocheck
8875+let map = (arr, value) => {
8876+ value
8877+}
8878+
8879+// opening Array would shadow our previously defined `map`
8880+// `open!` will explicitly turn off the automatic warning
8881+open! Array
8882+let arr = map([1,2,3], (a) => { a + 1})
8883+```
8884+
8885+**Note:** Same as with `open`, don't overuse `open!` statements if not necessary. Use (sub)modules to prevent shadowing issues.
8886+
8887+### Destructuring modules
8888+
8889+**Since 9.0.2**
8890+
8891+As an alternative to `open`ing a module, you can also destructure a module's functions and values into separate let bindings (similarly on how we'd destructure an object in JavaScript).
8892+
8893+<CodeTab labels={["ReScript", "JS Output"]}>
8894+
8895+```res nocheck
8896+module User = {
8897+ let user1 = "Anna"
8898+ let user2 = "Franz"
8899+}
8900+
8901+// Destructure by name
8902+let {user1, user2} = module(User)
8903+
8904+// Destructure with different alias
8905+let {user1: anna, user2: franz} = module(User)
8906+```
8907+
8908+```js
8909+var user1 = "Anna";
8910+
8911+var user2 = "Franz";
8912+
8913+var User = {
8914+ user1: user1,
8915+ user2: user2,
8916+};
8917+```
8918+
8919+</CodeTab>
8920+
8921+**Note:** You can't extract types with module destructuring — use a type alias instead (`type user = User.myUserType`).
8922+
8923+### Extending modules
8924+
8925+Using `include` in a module statically "spreads" a module's content into a new one, thus often fulfill the role of "inheritance" or "mixin".
8926+
8927+**Note**: this is equivalent to a compiler-level copy paste. **We heavily discourage `include`**. Use it as last resort!
8928+
8929+<CodeTab labels={["ReScript", "JS Output"]}>
8930+
8931+```res nocheck
8932+module BaseComponent = {
8933+ let defaultGreeting = "Hello"
8934+ let getAudience = (~excited) => excited ? "world!" : "world"
8935+}
8936+
8937+module ActualComponent = {
8938+ /* the content is copied over */
8939+ include BaseComponent
8940+ /* overrides BaseComponent.defaultGreeting */
8941+ let defaultGreeting = "Hey"
8942+ let render = () => defaultGreeting ++ " " ++ getAudience(~excited=true)
8943+}
8944+```
8945+
8946+```js
8947+function getAudience(excited) {
8948+ if (excited) {
8949+ return "world!";
8950+ } else {
8951+ return "world";
8952+ }
8953+}
8954+
8955+let BaseComponent = {
8956+ defaultGreeting: "Hello",
8957+ getAudience: getAudience,
8958+};
8959+
8960+let defaultGreeting = "Hey";
8961+
8962+function render() {
8963+ return defaultGreeting + " world!";
8964+}
8965+
8966+let ActualComponent = {
8967+ getAudience: getAudience,
8968+ defaultGreeting: defaultGreeting,
8969+ render: render,
8970+};
8971+
8972+export { BaseComponent, ActualComponent };
8973+```
8974+
8975+</CodeTab>
8976+
8977+**Note**: `open` and `include` are very different! The former brings a module's content into your current scope, so that you don't have to refer to a value by prefixing it with the module's name every time. The latter **copies over** the definition of a module statically, then also do an `open`.
8978+
8979+### Every `.res` file is a module
8980+
8981+Every ReScript file is itself compiled to a module of the same name as the file name, capitalized. The file `React.res` implicitly forms a module `React`, which can be seen by other source files.
8982+
8983+**Note**: ReScript file names should, by convention, be capitalized so that their casing matches their module name. Uncapitalized file names are not invalid, but will be implicitly transformed into a capitalized module name. I.e. `file.res` will be compiled into the module `File`. To simplify and minimize the disconnect here, the convention is therefore to capitalize file names.
8984+
8985+## Signatures
8986+
8987+A module's type is called a "signature", and can be written explicitly. If a
8988+module is like a `.res` (implementation) file, then a module's signature is like
8989+a `.resi` (interface) file.
8990+
8991+### Creation
8992+
8993+To create a signature, use the `module type` keyword. The signature name must start with a
8994+**capital letter**. Whatever you could place in a `.resi` file, you may place
8995+inside a signature definition's `{}` block.
8996+
8997+<CodeTab labels={["ReScript", "JS Output"]}>
8998+
8999+```res nocheck
9000+/* Using the types defined above */
9001+module type EstablishmentType = {
9002+ type profession
9003+ let getProfession: profession => string
9004+}
9005+```
9006+
9007+```js
9008+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
9009+```
9010+
9011+</CodeTab>
9012+
9013+A signature defines the list of requirements that a module must satisfy in order
9014+for that module to match the signature. Those requirements are of the form:
9015+
9016+- `let x: int` requires a `let` binding named `x`, of type `int`.
9017+- `type t = someType` requires a type field `t` to be equal to `someType`.
9018+- `type t` requires a type field `t`, but without imposing any requirements on the actual, concrete type of `t`. We'd use `t` in other entries in the signature to describe relationships, e.g. `let makePair: t => (t, t)` but we cannot, for example, assume that `t` is an `int`. This gives us great, enforced abstraction abilities.
9019+
9020+To illustrate the various kinds of type entries, consider the above signature
9021+`EstablishmentType` which requires that a module:
9022+
9023+- Declare a type named `profession`.
9024+- Must include a function that takes in a value of the type `profession` and returns a string.
9025+
9026+**Note**:
9027+
9028+Modules of the type `EstablishmentType` can contain more fields than the
9029+signature declares, just like the module `School` defined above (if we
9030+choose to assign it the type `EstablishmentType`. Otherwise, `School` exposes
9031+every field). This effectively makes the `person1` field an enforced
9032+implementation detail! Outsiders can't access it, since it's not present in the
9033+signature; the signature **constrained** what others can access.
9034+
9035+The type `EstablishmentType.profession` is **abstract**: it doesn't have a
9036+concrete type; it's saying "I don't care what the actual type is, but it's used
9037+as input to `getProfession`". This is useful to fit many modules under the same
9038+interface:
9039+
9040+<CodeTab labels={["ReScript", "JS Output"]}>
9041+
9042+```res nocheck
9043+module Company: EstablishmentType = {
9044+ type profession = CEO | Designer | Engineer | ...
9045+
9046+ let getProfession = (person) => ...
9047+ let person1 = ...
9048+ let person2 = ...
9049+}
9050+```
9051+
9052+```js
9053+function getProfession(person) {
9054+ ...
9055+}
9056+
9057+var person1 = ...
9058+
9059+var person2 = ...
9060+
9061+var Company = {
9062+ getProfession: getProfession,
9063+ person1: person1,
9064+ person2: person2
9065+};
9066+```
9067+
9068+</CodeTab>
9069+
9070+It's also useful to hide the underlying type as an implementation detail others
9071+can't rely on. If you ask what the type of `Company.profession` is, instead of
9072+exposing the variant, it'll only tell you "it's `Company.profession`".
9073+
9074+This also means that the compiler can't make assumptions about the type.
9075+In certain cases, when working with abstract types and `option` for example, the compiler doesn't know whether
9076+the abstract type can be the JavaScript value `undefined` or not. This can lead to less optimal code being generated.
9077+For this reason, you can use the `@notUndefined` decorator to tell the compiler that the abstract type can never be `undefined`
9078+(use with caution and see the `@notUndefined` decorator documentation for more details and caveats).
9079+
9080+### Extending module signatures
9081+
9082+Like modules themselves, module signatures can also be extended by other module signatures using `include`. Again, **heavily discouraged**:
9083+
9084+<CodeTab labels={["ReScript", "JS Output"]}>
9085+
9086+```res nocheck
9087+module type BaseComponent = {
9088+ let defaultGreeting: string
9089+ let getAudience: (~excited: bool) => string
9090+}
9091+
9092+module type ActualComponent = {
9093+ /* the BaseComponent signature is copied over */
9094+ include BaseComponent
9095+ let render: unit => string
9096+}
9097+```
9098+
9099+```js
9100+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
9101+```
9102+
9103+</CodeTab>
9104+
9105+**Note**: `BaseComponent` is a module **type**, not an actual module itself!
9106+
9107+If you do not have a defined module type, you can extract it from an actual module
9108+using `include (module type of ActualModuleName)`. For example, we can extend the
9109+`List` module from the standard library, which does not define a module
9110+type.
9111+
9112+<CodeTab labels={["ReScript", "JS Output"]}>
9113+
9114+```res nocheck
9115+module type MyList = {
9116+ include (module type of List)
9117+ let myListFun: list<'a> => list<'a>
9118+}
9119+```
9120+
9121+```js
9122+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
9123+```
9124+
9125+</CodeTab>
9126+
9127+### Every `.resi` file is a signature
9128+
9129+Similar to how a `React.res` file implicitly defines a module `React`, a file
9130+`React.resi` implicitly defines a signature for `React`. If `React.resi` isn't
9131+provided, the signature of `React.res` defaults to exposing all the fields of the
9132+module. Because they don't contain implementation files, `.resi` files are used
9133+in the ecosystem to also document the public API of their corresponding modules.
9134+
9135+<CodeTab labels={["ReScript", "JS Output"]}>
9136+
9137+```res nocheck
9138+/* file React.res (implementation. Compiles to module React) */
9139+type state = int
9140+let render = (str) => str
9141+```
9142+
9143+```js
9144+function render(str) {
9145+ return str;
9146+}
9147+
9148+export { render };
9149+```
9150+
9151+</CodeTab>
9152+
9153+```res sig
9154+/* file React.resi (interface. Compiles to the signature of React.res) */
9155+type state = int
9156+let render: string => string
9157+```
9158+
9159+## Module Functions (functors)
9160+
9161+Modules can be passed to functions! It would be the equivalent of passing a file
9162+as a first-class item. However, modules are at a different "layer" of the
9163+language than other common concepts, so we can't pass them to _regular_
9164+functions. Instead, we pass them to special functions called "functors".
9165+
9166+The syntax for defining and using functors is very much like the syntax
9167+for defining and using regular functions. The primary differences are:
9168+
9169+- Functors use the `module` keyword instead of `let`.
9170+- Functors take modules as arguments and return a module.
9171+- Functors _require_ annotating arguments.
9172+- Functors must start with a capital letter (just like modules/signatures).
9173+
9174+Here's an example `MakeSet` functor, that takes in a module of the type
9175+`Comparable` and returns a new set that can contain such comparable items.
9176+
9177+<CodeTab labels={["ReScript", "JS Output"]}>
9178+
9179+```res prelude
9180+module type Comparable = {
9181+ type t
9182+ let equal: (t, t) => bool
9183+}
9184+
9185+module MakeSet = (Item: Comparable) => {
9186+ // let's use a list as our naive backing data structure
9187+ type backingType = list<Item.t>
9188+ let empty = list{}
9189+ let add = (currentSet: backingType, newItem: Item.t): backingType =>
9190+ // if item exists
9191+ if currentSet->List.some(x => Item.equal(x, newItem)) {
9192+ currentSet // return the same (immutable) set (a list really)
9193+ } else {
9194+ list{
9195+ newItem,
9196+ ...currentSet // prepend to the set and return it
9197+ }
9198+ }
9199+}
9200+```
9201+
9202+```js
9203+var List = require("./stdlib/list.js");
9204+
9205+function MakeSet(Item) {
9206+ var add = function (currentSet, newItem) {
9207+ if (
9208+ List.exists(function (x) {
9209+ return Item.equal(x, newItem);
9210+ }, currentSet)
9211+ ) {
9212+ return currentSet;
9213+ } else {
9214+ return {
9215+ hd: newItem,
9216+ tl: currentSet,
9217+ };
9218+ }
9219+ };
9220+ return {
9221+ empty: /* [] */ 0,
9222+ add: add,
9223+ };
9224+}
9225+```
9226+
9227+</CodeTab>
9228+
9229+Functors can be applied using function application syntax. In this case, we're
9230+creating a set, whose items are pairs of integers.
9231+
9232+<CodeTab labels={["ReScript", "JS Output"]}>
9233+
9234+```res nocheck
9235+module IntPair = {
9236+ type t = (int, int)
9237+ let equal = ((x1: int, y1: int), (x2, y2)) => x1 == x2 && y1 == y2
9238+ let create = (x, y) => (x, y)
9239+}
9240+
9241+/* IntPair abides by the Comparable signature required by MakeSet */
9242+module SetOfIntPairs = MakeSet(IntPair)
9243+```
9244+
9245+```js
9246+import * as Stdlib_List from "@rescript/runtime/lib/es6/Stdlib_List.js";
9247+
9248+function MakeSet(Item) {
9249+ let add = (currentSet, newItem) => {
9250+ if (Stdlib_List.some(currentSet, (x) => Item.equal(x, newItem))) {
9251+ return currentSet;
9252+ } else {
9253+ return {
9254+ hd: newItem,
9255+ tl: currentSet,
9256+ };
9257+ }
9258+ };
9259+ return {
9260+ empty: /* [] */ 0,
9261+ add: add,
9262+ };
9263+}
9264+
9265+function equal(param, param$1) {
9266+ if (param[0] === param$1[0]) {
9267+ return param[1] === param$1[1];
9268+ } else {
9269+ return false;
9270+ }
9271+}
9272+
9273+function create(x, y) {
9274+ return [x, y];
9275+}
9276+
9277+let IntPair = {
9278+ equal: equal,
9279+ create: create,
9280+};
9281+
9282+function add(currentSet, newItem) {
9283+ if (Stdlib_List.some(currentSet, (x) => equal(x, newItem))) {
9284+ return currentSet;
9285+ } else {
9286+ return {
9287+ hd: newItem,
9288+ tl: currentSet,
9289+ };
9290+ }
9291+}
9292+
9293+let SetOfIntPairs = {
9294+ empty: /* [] */ 0,
9295+ add: add,
9296+};
9297+
9298+export { MakeSet, IntPair, SetOfIntPairs };
9299+```
9300+
9301+</CodeTab>
9302+
9303+### Module functions types
9304+
9305+Like with module types, functor types also act to constrain and hide what we may
9306+assume about functors. The syntax for functor types are consistent with those
9307+for function types, but with types capitalized to represent the signatures of
9308+modules the functor accepts as arguments and return values. In the
9309+previous example, we're exposing the backing type of a set; by giving `MakeSet`
9310+a functor signature, we can hide the underlying data structure!
9311+
9312+<CodeTab labels={["ReScript", "JS Output"]}>
9313+
9314+```res nocheck
9315+module type Comparable = ...
9316+
9317+module type MakeSetType = (Item: Comparable) => {
9318+ type backingType
9319+ let empty: backingType
9320+ let add: (backingType, Item.t) => backingType
9321+}
9322+
9323+module MakeSet: MakeSetType = (Item: Comparable) => {
9324+ ...
9325+}
9326+```
9327+
9328+```js
9329+// Empty output
9330+```
9331+
9332+</CodeTab>
9333+
9334+## Exotic Module Filenames
9335+
9336+**Since 8.3**
9337+
9338+It is possible to use non-conventional characters in your filenames (which is sometimes needed for specific JS frameworks). Here are some examples:
9339+
9340+- `src/Button.ios.res`
9341+- `pages/[id].res`
9342+
9343+Please note that modules with an exotic filename will not be accessible from other ReScript modules and will only produce JavaScript files.
9344+
9345+## Tips & Tricks
9346+
9347+Modules and functors are at a different "layer" of language than the rest (functions, let bindings, data structures, etc.). For example, you can't easily pass them into a tuple or record. Use them judiciously, if ever! Lots of times, just a record or a function is enough.
9348+
9349+---
9350+title: "Mutation"
9351+description: "Imperative and mutative programming capabilities in ReScript"
9352+canonical: "/docs/manual/mutation"
9353+section: "Language Features"
9354+order: 17
9355+---
9356+
9357+# Mutation
9358+
9359+ReScript has great traditional imperative & mutative programming capabilities. You should use these features sparingly, but sometimes they allow your code to be more performant and written in a more familiar pattern.
9360+
9361+## Mutate Let-binding
9362+
9363+Let-bindings are immutable, but you can wrap it with a `ref`, exposed as a record with a single mutable field in the standard library:
9364+
9365+<CodeTab labels={["ReScript", "JS Output"]}>
9366+
9367+```res prelude
9368+let myValue = ref(5)
9369+```
9370+
9371+```js
9372+var myValue = {
9373+ contents: 5,
9374+};
9375+```
9376+
9377+</CodeTab>
9378+
9379+## Usage
9380+
9381+You can get the actual value of a `ref` box through accessing its `contents` field:
9382+
9383+<CodeTab labels={["ReScript", "JS Output"]}>
9384+
9385+```res
9386+let five = myValue.contents // 5
9387+```
9388+
9389+```js
9390+let myValue = {
9391+ contents: 5,
9392+};
9393+
9394+let five = myValue.contents;
9395+
9396+export { myValue, five };
9397+```
9398+
9399+</CodeTab>
9400+
9401+Assign a new value to `myValue` like so:
9402+
9403+<CodeTab labels={["ReScript", "JS Output"]}>
9404+
9405+```res
9406+myValue.contents = 6
9407+```
9408+
9409+```js
9410+let myValue = {
9411+ contents: 5,
9412+};
9413+
9414+myValue.contents = 6;
9415+
9416+export { myValue };
9417+```
9418+
9419+</CodeTab>
9420+
9421+We provide a syntax sugar for this:
9422+
9423+<CodeTab labels={["ReScript", "JS Output"]}>
9424+
9425+```res
9426+myValue := 6
9427+```
9428+
9429+```js
9430+let myValue = {
9431+ contents: 5,
9432+};
9433+
9434+myValue.contents = 6;
9435+
9436+export { myValue };
9437+```
9438+
9439+</CodeTab>
9440+
9441+Note that the previous binding `five` stays `5`, since it got the underlying item on the `ref` box, not the `ref` itself.
9442+
9443+**Note**: you might see in the JS output tabs above that `ref` allocates an object. Worry not; local, non-exported `ref`s allocations are optimized away.
9444+
9445+## Tip & Tricks
9446+
9447+Before reaching for `ref`, know that you can achieve lightweight, local "mutations" through [overriding let bindings](./let-binding.mdx#binding-shadowing).
9448+
9449+---
9450+title: "Null, Undefined and Option"
9451+description: "JS interop with nullable and optional values in ReScript"
9452+canonical: "/docs/manual/null-undefined-option"
9453+section: "Language Features"
9454+order: 11
9455+---
9456+
9457+# Null, Undefined and Option
9458+
9459+ReScript itself doesn't have the notion of `null` or `undefined`. This is a _great_ thing, as it wipes out an entire category of bugs. No more `undefined is not a function`, and `cannot access someAttribute of undefined`!
9460+
9461+However, the **concept** of a potentially nonexistent value is still useful, and safely exists in our language.
9462+
9463+We represent the existence and nonexistence of a value by wrapping it with the `option` type. Here's its definition from the standard library:
9464+
9465+<CodeTab labels={["ReScript", "JS Output"]}>
9466+
9467+```res
9468+type option<'a> = None | Some('a)
9469+```
9470+
9471+```js
9472+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
9473+```
9474+
9475+</CodeTab>
9476+
9477+It means "a value of type option is either None (representing nothing) or that actual value wrapped in a Some".
9478+
9479+**Note** how the `option` type is just a regular [variant](./variant.mdx).
9480+
9481+## Example
9482+
9483+Here's a normal value:
9484+
9485+<CodeTab labels={["ReScript", "JS Output"]}>
9486+
9487+```res
9488+let licenseNumber = 5
9489+```
9490+
9491+```js
9492+let licenseNumber = 5;
9493+
9494+export { licenseNumber };
9495+```
9496+
9497+</CodeTab>
9498+
9499+To represent the concept of "maybe null", you'd turn this into an `option` type by wrapping it. For the sake of a more illustrative example, we'll put a condition around it:
9500+
9501+<CodeTab labels={["ReScript", "JS Output"]}>
9502+
9503+```res nocheck
9504+let licenseNumber =
9505+ if personHasACar {
9506+ Some(5)
9507+ } else {
9508+ None
9509+ }
9510+```
9511+
9512+```js
9513+var licenseNumber = personHasACar ? 5 : undefined;
9514+```
9515+
9516+</CodeTab>
9517+
9518+Later on, when another piece of code receives such value, it'd be forced to handle both cases through [pattern matching](./pattern-matching-destructuring.mdx):
9519+
9520+<CodeTab labels={["ReScript", "JS Output"]}>
9521+
9522+```res nocheck
9523+switch licenseNumber {
9524+| None =>
9525+ Console.log("The person doesn't have a car")
9526+| Some(number) =>
9527+ Console.log("The person's license number is " ++ Int.toString(number))
9528+}
9529+```
9530+
9531+```js
9532+var number = licenseNumber;
9533+
9534+if (number !== undefined) {
9535+ console.log("The person's license number is " + number.toString());
9536+} else {
9537+ console.log("The person doesn't have a car");
9538+}
9539+```
9540+
9541+</CodeTab>
9542+
9543+By turning your ordinary number into an `option` type, and by forcing you to handle the `None` case, the language effectively removed the possibility for you to mishandle, or forget to handle, a conceptual `null` value! **A pure ReScript program doesn't have null errors**.
9544+
9545+## Interoperate with JavaScript `undefined` and `null`
9546+
9547+The `option` type is common enough that we special-case it when compiling to JavaScript:
9548+
9549+<CodeTab labels={["ReScript", "JS Output"]}>
9550+
9551+```res
9552+let x = Some(5)
9553+```
9554+
9555+```js
9556+let x = 5;
9557+
9558+export { x };
9559+```
9560+
9561+</CodeTab>
9562+
9563+simply compiles down to `5`, and
9564+
9565+<CodeTab labels={["ReScript", "JS Output"]}>
9566+
9567+```res
9568+let x = None
9569+```
9570+
9571+```js
9572+let x;
9573+
9574+export { x };
9575+```
9576+
9577+</CodeTab>
9578+
9579+compiles to `undefined`! If you've got e.g. a string in JavaScript that you know might be `undefined`, type it as `option<string>` and you're done! Likewise, you can send a `Some(5)` or `None` to the JS side and expect it to be interpreted correctly =)
9580+
9581+### Caveat 1
9582+
9583+Unfortunately, lots of times, your JavaScript value might be _both_ `null` or `undefined`. In that case, you unfortunately can't type such value as e.g. `option<int>`, since our `option` type only checks for `undefined` and not `null` when dealing with a `None`.
9584+
9585+#### Solution: More Sophisticated `undefined` & `null` Interop
9586+
9587+To solve this, we provide access to more elaborate `null` and `undefined` helpers through the [`Nullable`](/docs/manual/api/stdlib/nullable) module. This somewhat works like an `option` type, but is different from it.
9588+
9589+#### Examples
9590+
9591+To create a JS `null`, use the value `Nullable.null`. To create a JS `undefined`, use `Nullable.undefined` (you can naturally use `None` too, but that's not the point here; the `Nullable.*` helpers wouldn't work with it).
9592+
9593+If you're receiving, for example, a JS string that can be `null` and `undefined`, type it as:
9594+
9595+<CodeTab labels={["ReScript", "JS Output"]}>
9596+
9597+```res
9598+@module("MyConstant") external myId: Nullable.t<string> = "myId"
9599+```
9600+
9601+```js
9602+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
9603+```
9604+
9605+</CodeTab>
9606+
9607+To create such a nullable string from our side (presumably to pass it to the JS side, for interop purpose), do:
9608+
9609+<CodeTab labels={["ReScript", "JS Output"]}>
9610+
9611+```res
9612+@module("MyIdValidator") external validate: Nullable.t<string> => bool = "validate"
9613+let personId: Nullable.t<string> = Nullable.make("abc123")
9614+
9615+let result = validate(personId)
9616+```
9617+
9618+```js
9619+import * as MyIdValidator from "MyIdValidator";
9620+
9621+let personId = "abc123";
9622+
9623+let result = MyIdValidator.validate(personId);
9624+
9625+export { personId, result };
9626+```
9627+
9628+</CodeTab>
9629+
9630+The `return` part "wraps" a string into a nullable string, to make the type system understand and track the fact that, as you pass this value around, it's not just a string, but a string that can be `null` or `undefined`.
9631+
9632+#### Convert to/from `option`
9633+
9634+`Nullable.fromOption` converts from a `option` to `Nullable.t`. `Nullable.toOption` does the opposite.
9635+
9636+---
9637+title: "Object"
9638+description: "Interoping with JS objects in ReScript"
9639+canonical: "/docs/manual/object"
9640+section: "Language Features"
9641+order: 7
9642+---
9643+
9644+# Object
9645+
9646+ReScript objects are like [records](./record.mdx), but:
9647+
9648+- No type declaration needed.
9649+- Structural and more polymorphic, [unlike records](./record.mdx#record-types-are-found-by-field-name).
9650+- Doesn't support updates unless the object comes from the JS side.
9651+- Doesn't support [pattern matching](./pattern-matching-destructuring.mdx).
9652+
9653+{/* TODO: support update man */}
9654+
9655+Although ReScript records compile to clean JavaScript objects, ReScript objects are a better candidate for emulating/binding to JS objects, as you'll see.
9656+
9657+## Type Declaration
9658+
9659+**Optional**, unlike for records. The type of an object is inferred from the value, so you never really need to write down its type definition. Nevertheless, here's its type declaration syntax:
9660+
9661+<CodeTab labels={["ReScript", "JS Output"]}>
9662+
9663+```res prelude
9664+type person = {
9665+ "age": int,
9666+ "name": string
9667+};
9668+```
9669+
9670+```js
9671+// Empty output
9672+```
9673+
9674+</CodeTab>
9675+
9676+Visually similar to record type's syntax, with the field names quoted.
9677+
9678+{/* TODO: document {.} and {..} */}
9679+
9680+## Creation
9681+
9682+To create a new object:
9683+
9684+<CodeTab labels={["ReScript", "JS Output"]}>
9685+
9686+```res
9687+let me = {
9688+ "age": 5,
9689+ "name": "Big ReScript"
9690+}
9691+```
9692+
9693+```js
9694+let me = {
9695+ age: 5,
9696+ name: "Big ReScript",
9697+};
9698+
9699+export { me };
9700+```
9701+
9702+</CodeTab>
9703+
9704+**Note**: as said above, unlike for record, this `me` value does **not** try to find a conforming type declaration with the field `"age"` and `"name"`; rather, the type of `me` is inferred as `{"age": int, "name": string}`. This is convenient, but also means this code passes type checking without errors:
9705+
9706+<CodeTab labels={["ReScript", "JS Output"]}>
9707+
9708+```res nocheck
9709+type person = {
9710+ "age": int
9711+};
9712+
9713+let me = {
9714+ "age": "hello!" // age is a string. No error.
9715+}
9716+```
9717+
9718+```js
9719+var me = {
9720+ age: "hello!",
9721+};
9722+```
9723+
9724+</CodeTab>
9725+
9726+Since the type checker doesn't try to match `me` with the type `person`. If you ever want to force an object value to be of a predeclared object type, just annotate the value:
9727+
9728+```res nocheck
9729+let me: person = {
9730+ "age": "hello!"
9731+}
9732+```
9733+
9734+Now the type system will error properly.
9735+
9736+## Access
9737+
9738+<CodeTab labels={["ReScript", "JS Output"]}>
9739+
9740+```res nocheck
9741+let age = me["age"]
9742+```
9743+
9744+```js
9745+var age = me["age"];
9746+```
9747+
9748+</CodeTab>
9749+
9750+## Update
9751+
9752+Disallowed unless the object is a binding that comes from the JavaScript side. In that case, use `=`
9753+
9754+<CodeTab labels={["ReScript", "JS Output"]}>
9755+
9756+```res
9757+type student = {
9758+ @set "age": int,
9759+ @set "name": string,
9760+}
9761+@module("MyJSFile") external student1: student = "student1"
9762+
9763+student1["name"] = "Mary"
9764+```
9765+
9766+```js
9767+import * as MyJSFile from "MyJSFile";
9768+
9769+MyJSFile.student1.name = "Mary";
9770+```
9771+
9772+</CodeTab>
9773+
9774+## Combine Types
9775+
9776+You can spread one object type definition into another using `...`:
9777+
9778+<CodeTab labels={["ReScript", "JS Output"]}>
9779+
9780+```res
9781+type point2d = {
9782+ "x": float,
9783+ "y": float,
9784+}
9785+type point3d = {
9786+ ...point2d,
9787+ "z": float,
9788+}
9789+
9790+let myPoint: point3d = {
9791+ "x": 1.0,
9792+ "y": 2.0,
9793+ "z": 3.0,
9794+}
9795+```
9796+
9797+```js
9798+let myPoint = {
9799+ x: 1.0,
9800+ y: 2.0,
9801+ z: 3.0,
9802+};
9803+
9804+export { myPoint };
9805+```
9806+
9807+</CodeTab>
9808+
9809+This only works with object types, not object values!
9810+
9811+## Tips & Tricks
9812+
9813+Since objects don't require type declarations, and since ReScript infers all the types for you, you get to very quickly and easily (and dangerously) bind to any JavaScript API. Check the JS output tab:
9814+
9815+<CodeTab labels={["ReScript", "JS Output"]}>
9816+
9817+```res
9818+// The type of document is just some random type 'a
9819+// that we won't bother to specify
9820+@val external document: 'a = "document"
9821+
9822+// call a method
9823+document["addEventListener"]("mouseup", _event => {
9824+ Console.log("clicked!")
9825+})
9826+
9827+// get a property
9828+let loc = document["location"]
9829+
9830+// set a property
9831+document["location"]["href"] = "rescript-lang.org"
9832+```
9833+
9834+```js
9835+document.addEventListener("mouseup", (_event) => {
9836+ console.log("clicked!");
9837+});
9838+
9839+let loc = document.location;
9840+
9841+document.location.href = "rescript-lang.org";
9842+
9843+export { loc };
9844+```
9845+
9846+</CodeTab>
9847+
9848+The `external` feature and the usage of this trick are also documented in the [external](./external.mdx#tips--tricks) section later. It's an excellent way to start writing some ReScript code without worrying about whether bindings to a particular library exists.
9849+
9850+---
9851+title: "Overview"
9852+metaTitle: "Language Features Overview"
9853+description: "A quick overview of ReScript's syntax and language features"
9854+canonical: "/docs/manual/overview"
9855+section: "Language Features"
9856+order: 1
9857+---
9858+
9859+# Language Overview
9860+
9861+A concise reference of ReScript's syntax and core language features.
9862+
9863+If you already know JavaScript and want a quick syntax guide first, see [ReScript for JavaScript Developers](./rescript-for-javascript-developers.mdx).
9864+
9865+## Semicolons
9866+
9867+ReScript does not require semicolons. Line breaks are sufficient to separate statements.
9868+
9869+## Comments
9870+
9871+| Syntax | Purpose |
9872+| -------------------------------- | ---------------------- |
9873+| `// Line comment` | Single-line comment |
9874+| `/* Block comment */` | Multi-line comment |
9875+| `/** Doc comment */` | Documentation comment |
9876+| `/*** Standalone doc comment */` | Standalone doc comment |
9877+
9878+## Variables
9879+
9880+| Syntax | Description |
9881+| ------------------------------------- | ----------------------- |
9882+| `let x = 5` | Immutable binding |
9883+| `let x = ref(5); x := x.contents + 1` | Mutable value via `ref` |
9884+
9885+## Strings
9886+
9887+| Syntax | Description |
9888+| ------------------------- | -------------------- |
9889+| `"Hello world!"` | String literal |
9890+| `"hello " ++ "world"` | String concatenation |
9891+| `` `hello ${message}` `` | String interpolation |
9892+| `` sql`select ${col};` `` | Tagged template |
9893+
9894+Strings must use double quotes (`"`).
9895+
9896+## Booleans
9897+
9898+| Syntax | Description |
9899+| -------------------- | ------------------------------ |
9900+| `true`, `false` | Boolean literals |
9901+| `!` | Logical NOT |
9902+| `\|\|`, `&&` | Logical OR, AND |
9903+| `<=`, `>=`, `<`, `>` | Comparison operators |
9904+| `===`, `!==` | Referential (shallow) equality |
9905+| `==`, `!=` | Structural (deep) equality |
9906+
9907+There is no equality with implicit type casting.
9908+
9909+## Numbers
9910+
9911+| Syntax | Description |
9912+| ------------ | ---------------------------------- |
9913+| `3` | Integer literal |
9914+| `3.1415` | Float literal |
9915+| `3 + 4` | Addition (works for int and float) |
9916+| `2 / 3 * 4` | Division and multiplication |
9917+| `2.0 ** 3.0` | Exponentiation |
9918+| `5 % 3` | Modulo |
9919+
9920+Arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`) work for both `int` and `float`.
9921+
9922+## Records
9923+
9924+Records are typed, immutable-by-default data structures with named fields.
9925+
9926+| Syntax | Description |
9927+| --------------------------------------- | -------------------- |
9928+| `type point = {x: int, mutable y: int}` | Type declaration |
9929+| `{x: 30, y: 20}` | Record creation |
9930+| `point.x` | Field access |
9931+| `point.y = 30` | Mutable field update |
9932+| `{...point, x: 30}` | Immutable update |
9933+
9934+## Arrays
9935+
9936+| Syntax | Description |
9937+| ----------------- | ---------------------- |
9938+| `[1, 2, 3]` | Array literal |
9939+| `myArray[1] = 10` | Mutable element update |
9940+
9941+Arrays are homogeneous. For mixed types, use tuples or [Untagged Variants](./variant.mdx#untagged-variants).
9942+
9943+## Tuples
9944+
9945+| Syntax | Description |
9946+| ------------------- | ------------------- |
9947+| `(1, "Bob", true)` | Tuple literal |
9948+| `let (a, b, c) = t` | Tuple destructuring |
9949+
9950+Tuples are fixed-length, heterogeneous, and immutable.
9951+
9952+## Null & Option
9953+
9954+ReScript has no `null` or `undefined`. The `option` type represents the possible absence of a value:
9955+
9956+| Syntax | Description |
9957+| ------------ | --------------- |
9958+| `None` | No value |
9959+| `Some("hi")` | A present value |
9960+
9961+## Functions
9962+
9963+| Syntax | Description |
9964+| ----------------------------- | -------------------- |
9965+| `arg => retVal` | Anonymous function |
9966+| `let named = (arg) => retVal` | Named function |
9967+| `add(4, add(5, 6))` | Function application |
9968+
9969+## Async / Await
9970+
9971+| Syntax | Description |
9972+| ---------------------------------- | ------------------------------ |
9973+| `async (arg) => {...}` | Async anonymous function |
9974+| `let named = async (arg) => {...}` | Async named function |
9975+| `await somePromise` | Await a promise |
9976+| `async (arg): string => {...}` | Typed async (return type only) |
9977+
9978+## Blocks
9979+
9980+The last expression in a `{}` block is implicitly returned, including in function bodies.
9981+
9982+<table>
9983+ <thead>
9984+ <tr>
9985+ <th>Example</th>
9986+ <th>Description</th>
9987+ </tr>
9988+ </thead>
9989+ <tbody>
9990+ <tr>
9991+ <td>
9992+ ```
9993+ let myFun = (x, y) => {
9994+ let doubleX = x + x
9995+ let doubleY = y + y
9996+ doubleX + doubleY
9997+ }
9998+ ```
9999+ </td>
10000+ <td>Function body with implicit return</td>
10001+ </tr>
10002+ <tr>
10003+ <td>
10004+ ```
10005+ let result = {
10006+ let x = 23
10007+ let y = 34
10008+ x + y
10009+ }
10010+ ```
10011+ </td>
10012+ <td>Block expression bound to a variable</td>
10013+ </tr>
10014+ </tbody>
10015+</table>
10016+
10017+## If-Else
10018+
10019+| Syntax | Description |
10020+| ------------------- | ------------------------------------------------------------------------ |
10021+| `if a {b} else {c}` | Conditional expression |
10022+| `a ? b : c` | Ternary expression |
10023+| `switch` | Pattern matching — [see full docs](./pattern-matching-destructuring.mdx) |
10024+
10025+Conditionals are expressions: `let result = if a {"hello"} else {"bye"}`
10026+
10027+## Destructuring
10028+
10029+| Syntax | Description |
10030+| --------------------------- | ------------------------- |
10031+| `let {a, b} = data` | Record destructuring |
10032+| `let [a, b] = data` | Array destructuring \* |
10033+| `let {a: aa, b: bb} = data` | Destructuring with rename |
10034+
10035+\* The compiler warns if `data` might not be of length 2.
10036+
10037+## Loops
10038+
10039+| Syntax | Description |
10040+| ---------------------------- | --------------- |
10041+| `for i in 0 to 10 {...}` | Ascending loop |
10042+| `for i in 10 downto 0 {...}` | Descending loop |
10043+| `while true {...}` | While loop |
10044+
10045+## JSX
10046+
10047+| Syntax | Description |
10048+| ----------------------------------------- | ---------------------- |
10049+| `<Comp message="hi" onClick={handler} />` | Props |
10050+| `<Comp message />` | Argument punning |
10051+| `<input checked=true />` | Explicit boolean props |
10052+| `<Comp>...children</Comp>` | Children spread |
10053+
10054+## Exceptions
10055+
10056+| Syntax | Description |
10057+| --------------------------------------------- | --------------------- |
10058+| `throw(SomeException(...))` | Raise an exception |
10059+| `try a catch { \| SomeException(err) => ...}` | Catch an exception \* |
10060+
10061+\* There is no `finally` clause.
10062+
10063+## Compilation Output Reference
10064+
10065+A reference showing how common ReScript features compile to JavaScript.
10066+
10067+| Feature | ReScript | JavaScript Output |
10068+| ------------------------- | ------------------------------------ | ------------------------------------------ |
10069+| String | `"Hello"` | `"Hello"` |
10070+| String Interpolation | `` `Hello ${message}` `` | `"Hello " + message` |
10071+| Character (discouraged) | `'x'` | `120` (char code) |
10072+| Integer | `23`, `-23` | `23`, `-23` |
10073+| Float | `23.0`, `-23.0` | `23.0`, `-23.0` |
10074+| Addition | `23 + 1` | `23 + 1` |
10075+| Float Addition | `23.0 + 1.0` | `23.0 + 1.0` |
10076+| Division/Multiply | `2 / 23 * 1` | `2 / 23 * 1` |
10077+| Float Division/Multiply | `2.0 / 23.0 * 1.0` | `2.0 / 23.0 * 1.0` |
10078+| Float Exponentiation | `2.0 ** 3.0` | `2.0 ** 3.0` |
10079+| String Concatenation | `"Hello " ++ "World"` | `"Hello " + "World"` |
10080+| Comparison | `>`, `<`, `>=`, `<=` | `>`, `<`, `>=`, `<=` |
10081+| Boolean operation | `!`, `&&`, `\|\|` | `!`, `&&`, `\|\|` |
10082+| Shallow and deep Equality | `===`, `==` | `===`, `==` |
10083+| List (discouraged) | `list{1, 2, 3}` | `{hd: 1, tl: {hd: 2, tl: {hd: 3, tl: 0}}}` |
10084+| List Prepend | `list{a1, a2, ...oldList}` | `{hd: a1, tl: {hd: a2, tl: theRest}}` |
10085+| Array | `[1, 2, 3]` | `[1, 2, 3]` |
10086+| Record | `type t = {b: int}; let a = {b: 10}` | `var a = {b: 10}` |
10087+| Multiline Comment | `/* Comment here */` | Not in output |
10088+| Single line Comment | `// Comment here` | Not in output |
10089+
10090+_Note that this is a cleaned-up reference table; some examples' JavaScript output may differ slightly in practice._
10091+
10092+---
10093+title: "Pattern Matching / Destructuring"
10094+description: "Pattern matching and destructuring complex data structures in ReScript"
10095+canonical: "/docs/manual/pattern-matching-destructuring"
10096+section: "Language Features"
10097+order: 16
10098+---
10099+
10100+# Pattern Matching / Destructuring
10101+
10102+One of ReScript's **best** features is our pattern matching. Pattern matching combines 3 brilliant features into one:
10103+
10104+- Destructuring.
10105+- `switch` based on shape of data.
10106+- Exhaustiveness check.
10107+
10108+We'll dive into each aspect below.
10109+
10110+## Destructuring
10111+
10112+Even JavaScript has destructuring, which is "opening up" a data structure to extract the parts we want and assign variable names to them:
10113+
10114+<CodeTab labels={["ReScript", "JS Output"]}>
10115+
10116+```res
10117+let coordinates = (10, 20, 30)
10118+let (x, _, _) = coordinates
10119+Console.log(x) // 10
10120+```
10121+
10122+```js
10123+console.log(10);
10124+
10125+let coordinates = [10, 20, 30];
10126+
10127+let x = 10;
10128+
10129+export { coordinates, x };
10130+```
10131+
10132+</CodeTab>
10133+
10134+Destructuring works with most built-in data structures:
10135+
10136+<CodeTab labels={["ReScript", "JS Output"]}>
10137+
10138+```res
10139+// Record
10140+type student = {name: string, age: int}
10141+let student1 = {name: "John", age: 10}
10142+let {name} = student1 // "John" assigned to `name`
10143+
10144+// Variant
10145+type result =
10146+ | Success(string)
10147+let myResult = Success("You did it!")
10148+let Success(message) = myResult // "You did it!" assigned to `message`
10149+```
10150+
10151+```js
10152+let student1 = {
10153+ name: "John",
10154+ age: 10,
10155+};
10156+
10157+let name = "John";
10158+
10159+let myResult = {
10160+ TAG: "Success",
10161+ _0: "You did it!",
10162+};
10163+
10164+let message = "You did it!";
10165+
10166+export { student1, name, myResult, message };
10167+```
10168+
10169+</CodeTab>
10170+
10171+You can also use destructuring anywhere you'd usually put a binding:
10172+
10173+<CodeTab labels={["ReScript", "JS Output"]}>
10174+
10175+```res
10176+type result =
10177+ | Success(string)
10178+let displayMessage = (Success(m)) => {
10179+ // we've directly extracted the success message
10180+ // string by destructuring the parameter
10181+ Console.log(m)
10182+}
10183+displayMessage(Success("You did it!"))
10184+```
10185+
10186+```js
10187+function displayMessage(m) {
10188+ console.log(m._0);
10189+}
10190+
10191+displayMessage({
10192+ TAG: "Success",
10193+ _0: "You did it!",
10194+});
10195+
10196+export { displayMessage };
10197+```
10198+
10199+</CodeTab>
10200+
10201+For a record, you can rename the field while destructuring:
10202+
10203+<CodeTab labels={["ReScript", "JS Output"]}>
10204+
10205+```res nocheck
10206+let {name: n} = student1 // "John" assigned to `n`
10207+```
10208+
10209+```js
10210+var n = "John";
10211+```
10212+
10213+</CodeTab>
10214+
10215+You _can_ in theory destructure array and list at the top level too:
10216+
10217+```res nocheck
10218+let myArray = [1, 2, 3]
10219+let [item1, item2, _] = myArray
10220+// 1 assigned to `item1`, 2 assigned to `item2`, 3rd item ignored
10221+
10222+let myList = list{1, 2, 3}
10223+let list{head, ...tail} = myList
10224+// 1 assigned to `head`, `list{2, 3}` assigned to tail
10225+```
10226+
10227+But the array example is **highly disrecommended** (use tuple instead) and the list example will error on you. They're only there for completeness' sake. As you'll see below, the proper way of using destructuring array and list is using `switch`.
10228+
10229+## `switch` Based on Shape of Data
10230+
10231+While the destructuring aspect of pattern matching is nice, it doesn't really change the way you think about structuring your code. One paradigm-changing way of thinking about your code is to execute some code based on the shape of the data.
10232+
10233+Consider a variant:
10234+
10235+<CodeTab labels={["ReScript", "JS Output"]}>
10236+
10237+```res prelude
10238+type payload =
10239+ | BadResult(int)
10240+ | GoodResult(string)
10241+ | NoResult
10242+```
10243+
10244+```js
10245+// Empty output
10246+```
10247+
10248+</CodeTab>
10249+
10250+We'd like to handle each of the 3 cases differently. For example, print a success message if the value is `GoodResult(...)`, do something else when the value is `NoResult`, etc.
10251+
10252+In other languages, you'd end up with a series of if-elses that are hard to read and error-prone. In ReScript, you can instead use the supercharged `switch` pattern matching facility to destructure the value while calling the right code based on what you destructured:
10253+
10254+<CodeTab labels={["ReScript", "JS Output"]}>
10255+
10256+```res
10257+let data = GoodResult("Product shipped!")
10258+switch data {
10259+| GoodResult(theMessage) =>
10260+ Console.log("Success! " ++ theMessage)
10261+| BadResult(errorCode) =>
10262+ Console.log("Something's wrong. The error code is: " ++ Int.toString(errorCode))
10263+| NoResult =>
10264+ Console.log("Bah.")
10265+}
10266+```
10267+
10268+```js
10269+let data = {
10270+ TAG: "GoodResult",
10271+ _0: "Product shipped!",
10272+};
10273+
10274+if (typeof data !== "object") {
10275+ console.log("Bah.");
10276+} else if (data.TAG === "BadResult") {
10277+ console.log(
10278+ "Something's wrong. The error code is: " + "Product shipped!".toString(),
10279+ );
10280+} else {
10281+ console.log("Success! Product shipped!");
10282+}
10283+
10284+export { data };
10285+```
10286+
10287+</CodeTab>
10288+
10289+In this case, `message` will have the value `"Success! Product shipped!"`.
10290+
10291+Suddenly, your if-elses that messily checks some structure of the value got turned into a clean, compiler-verified, linear list of code to execute based on exactly the shape of the value.
10292+
10293+### Complex Examples
10294+
10295+Here's a real-world scenario that'd be a headache to code in other languages. Given this data structure:
10296+
10297+<CodeTab labels={["ReScript", "JS Output"]}>
10298+
10299+```res prelude
10300+type status = Vacations(int) | Sabbatical(int) | Sick | Present
10301+type reportCard = {passing: bool, gpa: float}
10302+type student = {name: string, status: status, reportCard: reportCard}
10303+type person =
10304+ | Teacher({name: string, age: int})
10305+ | Student(student)
10306+```
10307+
10308+```js
10309+// Empty output
10310+```
10311+
10312+</CodeTab>
10313+
10314+Imagine this requirement:
10315+
10316+- Informally greet a person who's a teacher and if his name is Mary or Joe.
10317+- Greet other teachers formally.
10318+- If the person's a student, congratulate him/her score if they passed the semester.
10319+- If the student has a gpa of 0 and is on vacations or sabbatical, display a different message.
10320+- A catch-all message for a student.
10321+
10322+ReScript can do this easily!
10323+
10324+<CodeTab labels={["ReScript", "JS Output"]}>
10325+
10326+```res prelude
10327+let person1 = Teacher({name: "Jane", age: 35})
10328+
10329+let message = switch person1 {
10330+| Teacher({name: "Mary" | "Joe"}) =>
10331+ `Hey, still going to the party on Saturday?`
10332+| Teacher({name}) =>
10333+ // this is matched only if `name` isn't "Mary" or "Joe"
10334+ `Hello ${name}.`
10335+| Student({name, reportCard: {passing: true, gpa}}) =>
10336+ `Congrats ${name}, nice GPA of ${Float.toString(gpa)} you got there!`
10337+| Student({
10338+ reportCard: {gpa: 0.0},
10339+ status: Vacations(daysLeft) | Sabbatical(daysLeft)
10340+ }) =>
10341+ `Come back in ${Int.toString(daysLeft)} days!`
10342+| Student({status: Sick}) =>
10343+ `How are you feeling?`
10344+| Student({name}) =>
10345+ `Good luck next semester ${name}!`
10346+}
10347+```
10348+
10349+```js
10350+var person1 = {
10351+ TAG: "Teacher",
10352+ name: "Jane",
10353+ age: 35,
10354+};
10355+
10356+var message;
10357+
10358+if (person1.TAG === "Teacher") {
10359+ message = "Hello Jane.";
10360+} else {
10361+ var match = "Jane";
10362+ var match$1 = match.status;
10363+ var name = match.name;
10364+ var match$2 = match.reportCard;
10365+ if (match$2.passing) {
10366+ message =
10367+ "Congrats " +
10368+ name +
10369+ ", nice GPA of " +
10370+ match$2.gpa.toString() +
10371+ " you got there!";
10372+ } else {
10373+ var exit = 0;
10374+ if (typeof match$1 !== "object") {
10375+ message =
10376+ match$1 === "Sick"
10377+ ? "How are you feeling?"
10378+ : "Good luck next semester " + name + "!";
10379+ } else {
10380+ exit = 1;
10381+ }
10382+ if (exit === 1) {
10383+ message =
10384+ match.reportCard.gpa !== 0.0
10385+ ? "Good luck next semester " + name + "!"
10386+ : "Come back in " + match$1._0.toString() + " days!";
10387+ }
10388+ }
10389+}
10390+```
10391+
10392+</CodeTab>
10393+
10394+**Note** how we've:
10395+
10396+- drilled deep down into the value concisely
10397+- using a **nested pattern check** `"Mary" | "Joe"` and `Vacations | Sabbatical`
10398+- while extracting the `daysLeft` number from the latter case
10399+- and assigned the greeting to the binding `message`.
10400+
10401+Here's another example of pattern matching, this time on an inline tuple.
10402+
10403+<CodeTab labels={["ReScript", "JS Output"]}>
10404+
10405+```res nocheck
10406+type animal = Dog | Cat | Bird
10407+let categoryId = switch (isBig, myAnimal) {
10408+| (true, Dog) => 1
10409+| (true, Cat) => 2
10410+| (true, Bird) => 3
10411+| (false, Dog | Cat) => 4
10412+| (false, Bird) => 5
10413+}
10414+```
10415+
10416+```js
10417+var categoryId = isBig ? (myAnimal + 1) | 0 : myAnimal >= 2 ? 5 : 4;
10418+```
10419+
10420+</CodeTab>
10421+
10422+**Note** how pattern matching on a tuple is equivalent to a 2D table:
10423+
10424+| isBig \ myAnimal | Dog | Cat | Bird |
10425+| ---------------- | --- | --- | ---- |
10426+| true | 1 | 2 | 3 |
10427+| false | 4 | 4 | 5 |
10428+
10429+### Fall-Through Patterns
10430+
10431+The nested pattern check, demonstrated in the earlier `person` example, also works at the top level of a `switch`:
10432+
10433+<CodeTab labels={["ReScript", "JS Output"]}>
10434+
10435+```res prelude
10436+let myStatus = Vacations(10)
10437+
10438+switch myStatus {
10439+| Vacations(days)
10440+| Sabbatical(days) => Console.log(`Come back in ${Int.toString(days)} days!`)
10441+| Sick
10442+| Present => Console.log("Hey! How are you?")
10443+}
10444+```
10445+
10446+```js
10447+var myStatus = {
10448+ TAG: /* Vacations */ 0,
10449+ _0: 10,
10450+};
10451+
10452+if (typeof myStatus === "number") {
10453+ console.log("Hey! How are you?");
10454+} else {
10455+ console.log("Come back in " + (10).toString() + " days!");
10456+}
10457+```
10458+
10459+</CodeTab>
10460+
10461+Having multiple cases fall into the same handling can clean up certain types of logic.
10462+
10463+### Ignore Part of a Value
10464+
10465+If you have a value like `Teacher(payload)` where you just want to pattern match on the `Teacher` part and ignore the `payload` completely, you can use the `_` wildcard like this:
10466+
10467+<CodeTab labels={["ReScript", "JS Output"]}>
10468+
10469+```res
10470+switch person1 {
10471+| Teacher(_) => Console.log("Hi teacher")
10472+| Student(_) => Console.log("Hey student")
10473+}
10474+```
10475+
10476+```js
10477+let person1 = {
10478+ TAG: "Teacher",
10479+ name: "Jane",
10480+ age: 35,
10481+};
10482+
10483+let message;
10484+
10485+if (person1.TAG === "Teacher") {
10486+ message = `Hello ` + "Jane" + `.`;
10487+} else {
10488+ let match = "Jane";
10489+ let match$1 = match.status;
10490+ let name = match.name;
10491+ let match$2 = match.reportCard;
10492+ if (match$2.passing) {
10493+ message =
10494+ `Congrats ` +
10495+ name +
10496+ `, nice GPA of ` +
10497+ match$2.gpa.toString() +
10498+ ` you got there!`;
10499+ } else {
10500+ let exit = 0;
10501+ if (typeof match$1 !== "object") {
10502+ message =
10503+ match$1 === "Sick"
10504+ ? `How are you feeling?`
10505+ : `Good luck next semester ` + name + `!`;
10506+ } else {
10507+ exit = 1;
10508+ }
10509+ if (exit === 1) {
10510+ message =
10511+ match.reportCard.gpa !== 0.0
10512+ ? `Good luck next semester ` + name + `!`
10513+ : `Come back in ` + match$1._0.toString() + ` days!`;
10514+ }
10515+ }
10516+}
10517+
10518+let myStatus = {
10519+ TAG: "Vacations",
10520+ _0: 10,
10521+};
10522+
10523+let exit$1 = 0;
10524+
10525+if (typeof myStatus !== "object") {
10526+ console.log("Hey! How are you?");
10527+} else {
10528+ exit$1 = 1;
10529+}
10530+
10531+if (exit$1 === 1) {
10532+ console.log(`Come back in ` + (10).toString() + ` days!`);
10533+}
10534+
10535+if (person1.TAG === "Teacher") {
10536+ console.log("Hi teacher");
10537+} else {
10538+ console.log("Hey student");
10539+}
10540+
10541+export { person1, message, myStatus };
10542+```
10543+
10544+</CodeTab>
10545+
10546+`_` also works at the top level of the `switch`, serving as a catch-all condition:
10547+
10548+<CodeTab labels={["ReScript", "JS Output"]}>
10549+
10550+```res
10551+switch myStatus {
10552+| Vacations(_) => Console.log("Have fun!")
10553+| _ => Console.log("Ok.")
10554+}
10555+```
10556+
10557+```js
10558+let person1 = {
10559+ TAG: "Teacher",
10560+ name: "Jane",
10561+ age: 35,
10562+};
10563+
10564+let message;
10565+
10566+if (person1.TAG === "Teacher") {
10567+ message = `Hello ` + "Jane" + `.`;
10568+} else {
10569+ let match = "Jane";
10570+ let match$1 = match.status;
10571+ let name = match.name;
10572+ let match$2 = match.reportCard;
10573+ if (match$2.passing) {
10574+ message =
10575+ `Congrats ` +
10576+ name +
10577+ `, nice GPA of ` +
10578+ match$2.gpa.toString() +
10579+ ` you got there!`;
10580+ } else {
10581+ let exit = 0;
10582+ if (typeof match$1 !== "object") {
10583+ message =
10584+ match$1 === "Sick"
10585+ ? `How are you feeling?`
10586+ : `Good luck next semester ` + name + `!`;
10587+ } else {
10588+ exit = 1;
10589+ }
10590+ if (exit === 1) {
10591+ message =
10592+ match.reportCard.gpa !== 0.0
10593+ ? `Good luck next semester ` + name + `!`
10594+ : `Come back in ` + match$1._0.toString() + ` days!`;
10595+ }
10596+ }
10597+}
10598+
10599+let myStatus = {
10600+ TAG: "Vacations",
10601+ _0: 10,
10602+};
10603+
10604+let exit$1 = 0;
10605+
10606+if (typeof myStatus !== "object") {
10607+ console.log("Hey! How are you?");
10608+} else {
10609+ exit$1 = 1;
10610+}
10611+
10612+if (exit$1 === 1) {
10613+ console.log(`Come back in ` + (10).toString() + ` days!`);
10614+}
10615+
10616+if (typeof myStatus !== "object" || myStatus.TAG !== "Vacations") {
10617+ console.log("Ok.");
10618+} else {
10619+ console.log("Have fun!");
10620+}
10621+
10622+export { person1, message, myStatus };
10623+```
10624+
10625+</CodeTab>
10626+
10627+**Do not** abuse a top-level catch-all condition. Instead, prefer writing out all the cases:
10628+
10629+<CodeTab labels={["ReScript", "JS Output"]}>
10630+
10631+```res
10632+switch myStatus {
10633+| Vacations(_) => Console.log("Have fun!")
10634+| Sabbatical(_) | Sick | Present => Console.log("Ok.")
10635+}
10636+```
10637+
10638+```js
10639+let person1 = {
10640+ TAG: "Teacher",
10641+ name: "Jane",
10642+ age: 35,
10643+};
10644+
10645+let message;
10646+
10647+if (person1.TAG === "Teacher") {
10648+ message = `Hello ` + "Jane" + `.`;
10649+} else {
10650+ let match = "Jane";
10651+ let match$1 = match.status;
10652+ let name = match.name;
10653+ let match$2 = match.reportCard;
10654+ if (match$2.passing) {
10655+ message =
10656+ `Congrats ` +
10657+ name +
10658+ `, nice GPA of ` +
10659+ match$2.gpa.toString() +
10660+ ` you got there!`;
10661+ } else {
10662+ let exit = 0;
10663+ if (typeof match$1 !== "object") {
10664+ message =
10665+ match$1 === "Sick"
10666+ ? `How are you feeling?`
10667+ : `Good luck next semester ` + name + `!`;
10668+ } else {
10669+ exit = 1;
10670+ }
10671+ if (exit === 1) {
10672+ message =
10673+ match.reportCard.gpa !== 0.0
10674+ ? `Good luck next semester ` + name + `!`
10675+ : `Come back in ` + match$1._0.toString() + ` days!`;
10676+ }
10677+ }
10678+}
10679+
10680+let myStatus = {
10681+ TAG: "Vacations",
10682+ _0: 10,
10683+};
10684+
10685+let exit$1 = 0;
10686+
10687+if (typeof myStatus !== "object") {
10688+ console.log("Hey! How are you?");
10689+} else {
10690+ exit$1 = 1;
10691+}
10692+
10693+if (exit$1 === 1) {
10694+ console.log(`Come back in ` + (10).toString() + ` days!`);
10695+}
10696+
10697+if (typeof myStatus !== "object" || myStatus.TAG !== "Vacations") {
10698+ console.log("Ok.");
10699+} else {
10700+ console.log("Have fun!");
10701+}
10702+
10703+export { person1, message, myStatus };
10704+```
10705+
10706+</CodeTab>
10707+
10708+Slightly more verbose, but a one-time writing effort. This helps when you add a new variant case e.g. `Quarantined` to the `status` type and need to update the places that pattern match on it. A top-level wildcard here would have accidentally and silently continued working, potentially causing bugs.
10709+
10710+### If Clause
10711+
10712+Sometime, you want to check more than the shape of a value. You want to also run some arbitrary check on it. You might be tempted to write this:
10713+
10714+<CodeTab labels={["ReScript", "JS Output"]}>
10715+
10716+```res
10717+switch person1 {
10718+| Teacher(_) => () // do nothing
10719+| Student({reportCard: {gpa}}) =>
10720+ if gpa < 0.5 {
10721+ Console.log("What's happening")
10722+ } else {
10723+ Console.log("Heyo")
10724+ }
10725+}
10726+```
10727+
10728+```js
10729+let person1 = {
10730+ TAG: "Teacher",
10731+ name: "Jane",
10732+ age: 35,
10733+};
10734+
10735+let message;
10736+
10737+if (person1.TAG === "Teacher") {
10738+ message = `Hello ` + "Jane" + `.`;
10739+} else {
10740+ let match = "Jane";
10741+ let match$1 = match.status;
10742+ let name = match.name;
10743+ let match$2 = match.reportCard;
10744+ if (match$2.passing) {
10745+ message =
10746+ `Congrats ` +
10747+ name +
10748+ `, nice GPA of ` +
10749+ match$2.gpa.toString() +
10750+ ` you got there!`;
10751+ } else {
10752+ let exit = 0;
10753+ if (typeof match$1 !== "object") {
10754+ message =
10755+ match$1 === "Sick"
10756+ ? `How are you feeling?`
10757+ : `Good luck next semester ` + name + `!`;
10758+ } else {
10759+ exit = 1;
10760+ }
10761+ if (exit === 1) {
10762+ message =
10763+ match.reportCard.gpa !== 0.0
10764+ ? `Good luck next semester ` + name + `!`
10765+ : `Come back in ` + match$1._0.toString() + ` days!`;
10766+ }
10767+ }
10768+}
10769+
10770+let myStatus = {
10771+ TAG: "Vacations",
10772+ _0: 10,
10773+};
10774+
10775+let exit$1 = 0;
10776+
10777+if (typeof myStatus !== "object") {
10778+ console.log("Hey! How are you?");
10779+} else {
10780+ exit$1 = 1;
10781+}
10782+
10783+if (exit$1 === 1) {
10784+ console.log(`Come back in ` + (10).toString() + ` days!`);
10785+}
10786+
10787+if (person1.TAG !== "Teacher") {
10788+ if ("Jane".reportCard.gpa < 0.5) {
10789+ console.log("What's happening");
10790+ } else {
10791+ console.log("Heyo");
10792+ }
10793+}
10794+
10795+export { person1, message, myStatus };
10796+```
10797+
10798+</CodeTab>
10799+
10800+`switch` patterns support a shortcut for the arbitrary `if` check, to keep your pattern linear-looking:
10801+
10802+<CodeTab labels={["ReScript", "JS Output"]}>
10803+
10804+```res
10805+switch person1 {
10806+| Teacher(_) => () // do nothing
10807+| Student({reportCard: {gpa}}) if gpa < 0.5 =>
10808+ Console.log("What's happening")
10809+| Student(_) =>
10810+ // fall-through, catch-all case
10811+ Console.log("Heyo")
10812+}
10813+```
10814+
10815+```js
10816+let person1 = {
10817+ TAG: "Teacher",
10818+ name: "Jane",
10819+ age: 35,
10820+};
10821+
10822+let message;
10823+
10824+if (person1.TAG === "Teacher") {
10825+ message = `Hello ` + "Jane" + `.`;
10826+} else {
10827+ let match = "Jane";
10828+ let match$1 = match.status;
10829+ let name = match.name;
10830+ let match$2 = match.reportCard;
10831+ if (match$2.passing) {
10832+ message =
10833+ `Congrats ` +
10834+ name +
10835+ `, nice GPA of ` +
10836+ match$2.gpa.toString() +
10837+ ` you got there!`;
10838+ } else {
10839+ let exit = 0;
10840+ if (typeof match$1 !== "object") {
10841+ message =
10842+ match$1 === "Sick"
10843+ ? `How are you feeling?`
10844+ : `Good luck next semester ` + name + `!`;
10845+ } else {
10846+ exit = 1;
10847+ }
10848+ if (exit === 1) {
10849+ message =
10850+ match.reportCard.gpa !== 0.0
10851+ ? `Good luck next semester ` + name + `!`
10852+ : `Come back in ` + match$1._0.toString() + ` days!`;
10853+ }
10854+ }
10855+}
10856+
10857+let myStatus = {
10858+ TAG: "Vacations",
10859+ _0: 10,
10860+};
10861+
10862+let exit$1 = 0;
10863+
10864+if (typeof myStatus !== "object") {
10865+ console.log("Hey! How are you?");
10866+} else {
10867+ exit$1 = 1;
10868+}
10869+
10870+if (exit$1 === 1) {
10871+ console.log(`Come back in ` + (10).toString() + ` days!`);
10872+}
10873+
10874+if (person1.TAG !== "Teacher") {
10875+ if ("Jane".reportCard.gpa < 0.5) {
10876+ console.log("What's happening");
10877+ } else {
10878+ console.log("Heyo");
10879+ }
10880+}
10881+
10882+export { person1, message, myStatus };
10883+```
10884+
10885+</CodeTab>
10886+
10887+### Match on subtype variants
10888+
10889+You can refine a variant A to variant B using the [variant type spread syntax](./variant.mdx#variant-type-spreads) in pattern matching. This is possible if variant B [is a subtype of](./variant.mdx#coercion) variant A.
10890+
10891+Let's look at an example:
10892+
10893+<CodeTab labels={["ReScript", "JS Output"]}>
10894+
10895+```res
10896+type pets = Cat | Dog
10897+type fish = Cod | Salmon
10898+type animals = | ...pets | ...fish
10899+
10900+let greetPet = (pet: pets) => {
10901+ switch pet {
10902+ | Cat => Console.log("Hello kitty!")
10903+ | Dog => Console.log("Woof woof doggie!")
10904+ }
10905+}
10906+
10907+let greetFish = (fish: fish) => {
10908+ switch fish {
10909+ | Cod => Console.log("Blub blub..")
10910+ | Salmon => Console.log("Blub blub blub blub..")
10911+ }
10912+}
10913+
10914+let greetAnimal = (animal: animals) => {
10915+ switch animal {
10916+ | ...pets as pet => greetPet(pet)
10917+ | ...fish as fish => greetFish(fish)
10918+ }
10919+}
10920+```
10921+
10922+```js
10923+let person1 = {
10924+ TAG: "Teacher",
10925+ name: "Jane",
10926+ age: 35,
10927+};
10928+
10929+let message;
10930+
10931+if (person1.TAG === "Teacher") {
10932+ message = `Hello ` + "Jane" + `.`;
10933+} else {
10934+ let match = "Jane";
10935+ let match$1 = match.status;
10936+ let name = match.name;
10937+ let match$2 = match.reportCard;
10938+ if (match$2.passing) {
10939+ message =
10940+ `Congrats ` +
10941+ name +
10942+ `, nice GPA of ` +
10943+ match$2.gpa.toString() +
10944+ ` you got there!`;
10945+ } else {
10946+ let exit = 0;
10947+ if (typeof match$1 !== "object") {
10948+ message =
10949+ match$1 === "Sick"
10950+ ? `How are you feeling?`
10951+ : `Good luck next semester ` + name + `!`;
10952+ } else {
10953+ exit = 1;
10954+ }
10955+ if (exit === 1) {
10956+ message =
10957+ match.reportCard.gpa !== 0.0
10958+ ? `Good luck next semester ` + name + `!`
10959+ : `Come back in ` + match$1._0.toString() + ` days!`;
10960+ }
10961+ }
10962+}
10963+
10964+let myStatus = {
10965+ TAG: "Vacations",
10966+ _0: 10,
10967+};
10968+
10969+let exit$1 = 0;
10970+
10971+if (typeof myStatus !== "object") {
10972+ console.log("Hey! How are you?");
10973+} else {
10974+ exit$1 = 1;
10975+}
10976+
10977+if (exit$1 === 1) {
10978+ console.log(`Come back in ` + (10).toString() + ` days!`);
10979+}
10980+
10981+function greetPet(pet) {
10982+ if (pet === "Cat") {
10983+ console.log("Hello kitty!");
10984+ return;
10985+ }
10986+ console.log("Woof woof doggie!");
10987+}
10988+
10989+function greetFish(fish) {
10990+ if (fish === "Cod") {
10991+ console.log("Blub blub..");
10992+ return;
10993+ }
10994+ console.log("Blub blub blub blub..");
10995+}
10996+
10997+function greetAnimal(animal) {
10998+ switch (animal) {
10999+ case "Cat":
11000+ case "Dog":
11001+ return greetPet(animal);
11002+ case "Cod":
11003+ case "Salmon":
11004+ return greetFish(animal);
11005+ }
11006+}
11007+
11008+export { person1, message, myStatus, greetPet, greetFish, greetAnimal };
11009+```
11010+
11011+</CodeTab>
11012+
11013+Let's break down what we did:
11014+
11015+- Defined two different variants for pets and for fish
11016+- Wrote a dedicated function per animal type to greet that particular type of animal
11017+- Combined `pets` and `fish` into a main variant for `animals`
11018+- Wrote a function that can greet any animal by _spreading_ each sub variant on its own branch, aliasing that spread to a variable, and passing that variable to the dedicated greet function for that specific type
11019+
11020+Notice how we're able to match on parts of the main variant, as long as the variants are compatible.
11021+
11022+The example above aliases the variant type spread to a variable so we can use it in our branch. But, you can just as easily match without aliasing if you don't care about the value:
11023+
11024+<CodeTab labels={["ReScript", "JS Output"]}>
11025+
11026+```res nocheck
11027+let isPet = (animal: animals) => {
11028+ switch animal {
11029+ | ...pets => Console.log("A pet!")
11030+ | _ => Console.log("Not a pet...")
11031+ }
11032+}
11033+
11034+```
11035+
11036+```js
11037+function isPet(animal) {
11038+ switch (animal) {
11039+ case "Cat":
11040+ case "Dog":
11041+ console.log("A pet!");
11042+ return;
11043+ case "Cod":
11044+ case "Salmon":
11045+ console.log("Not a pet...");
11046+ return;
11047+ }
11048+}
11049+```
11050+
11051+</CodeTab>
11052+
11053+Similarily, if you want to get advanced, you can even pull out a single variant constructor. This works with and without aliases. Example:
11054+
11055+<CodeTab labels={["ReScript", "JS Output"]}>
11056+
11057+```res
11058+type dog = Dog
11059+type pets = Cat | ...dog
11060+type fish = Cod | Salmon
11061+type animals = | ...pets | ...fish
11062+
11063+let isPet = (animal: animals) => {
11064+ switch animal {
11065+ | ...dog => Console.log("A dog!")
11066+ | _ => Console.log("Not a dog...")
11067+ }
11068+}
11069+
11070+```
11071+
11072+```js
11073+let person1 = {
11074+ TAG: "Teacher",
11075+ name: "Jane",
11076+ age: 35,
11077+};
11078+
11079+let message;
11080+
11081+if (person1.TAG === "Teacher") {
11082+ message = `Hello ` + "Jane" + `.`;
11083+} else {
11084+ let match = "Jane";
11085+ let match$1 = match.status;
11086+ let name = match.name;
11087+ let match$2 = match.reportCard;
11088+ if (match$2.passing) {
11089+ message =
11090+ `Congrats ` +
11091+ name +
11092+ `, nice GPA of ` +
11093+ match$2.gpa.toString() +
11094+ ` you got there!`;
11095+ } else {
11096+ let exit = 0;
11097+ if (typeof match$1 !== "object") {
11098+ message =
11099+ match$1 === "Sick"
11100+ ? `How are you feeling?`
11101+ : `Good luck next semester ` + name + `!`;
11102+ } else {
11103+ exit = 1;
11104+ }
11105+ if (exit === 1) {
11106+ message =
11107+ match.reportCard.gpa !== 0.0
11108+ ? `Good luck next semester ` + name + `!`
11109+ : `Come back in ` + match$1._0.toString() + ` days!`;
11110+ }
11111+ }
11112+}
11113+
11114+let myStatus = {
11115+ TAG: "Vacations",
11116+ _0: 10,
11117+};
11118+
11119+let exit$1 = 0;
11120+
11121+if (typeof myStatus !== "object") {
11122+ console.log("Hey! How are you?");
11123+} else {
11124+ exit$1 = 1;
11125+}
11126+
11127+if (exit$1 === 1) {
11128+ console.log(`Come back in ` + (10).toString() + ` days!`);
11129+}
11130+
11131+function isPet(animal) {
11132+ if (animal === "Dog") {
11133+ console.log("A dog!");
11134+ return;
11135+ }
11136+ console.log("Not a dog...");
11137+}
11138+
11139+export { person1, message, myStatus, isPet };
11140+```
11141+
11142+</CodeTab>
11143+
11144+And, thanks to the rules of subtyping, the `Dog` constructor wouldn't _really_ need to be spread inside of the `pets` variant for this to work:
11145+
11146+<CodeTab labels={["ReScript", "JS Output"]}>
11147+
11148+```res
11149+type pets = Cat | Dog
11150+type fish = Cod | Salmon
11151+type animals = | ...pets | ...fish
11152+
11153+// Notice `dog` isn't spread into the `pets` variant,
11154+// but this still work due to subtyping.
11155+type dog = Dog
11156+
11157+let isPet = (animal: animals) => {
11158+ switch animal {
11159+ | ...dog => Console.log("A dog!")
11160+ | _ => Console.log("Not a dog...")
11161+ }
11162+}
11163+
11164+```
11165+
11166+```js
11167+let person1 = {
11168+ TAG: "Teacher",
11169+ name: "Jane",
11170+ age: 35,
11171+};
11172+
11173+let message;
11174+
11175+if (person1.TAG === "Teacher") {
11176+ message = `Hello ` + "Jane" + `.`;
11177+} else {
11178+ let match = "Jane";
11179+ let match$1 = match.status;
11180+ let name = match.name;
11181+ let match$2 = match.reportCard;
11182+ if (match$2.passing) {
11183+ message =
11184+ `Congrats ` +
11185+ name +
11186+ `, nice GPA of ` +
11187+ match$2.gpa.toString() +
11188+ ` you got there!`;
11189+ } else {
11190+ let exit = 0;
11191+ if (typeof match$1 !== "object") {
11192+ message =
11193+ match$1 === "Sick"
11194+ ? `How are you feeling?`
11195+ : `Good luck next semester ` + name + `!`;
11196+ } else {
11197+ exit = 1;
11198+ }
11199+ if (exit === 1) {
11200+ message =
11201+ match.reportCard.gpa !== 0.0
11202+ ? `Good luck next semester ` + name + `!`
11203+ : `Come back in ` + match$1._0.toString() + ` days!`;
11204+ }
11205+ }
11206+}
11207+
11208+let myStatus = {
11209+ TAG: "Vacations",
11210+ _0: 10,
11211+};
11212+
11213+let exit$1 = 0;
11214+
11215+if (typeof myStatus !== "object") {
11216+ console.log("Hey! How are you?");
11217+} else {
11218+ exit$1 = 1;
11219+}
11220+
11221+if (exit$1 === 1) {
11222+ console.log(`Come back in ` + (10).toString() + ` days!`);
11223+}
11224+
11225+function isPet(animal) {
11226+ if (animal === "Dog") {
11227+ console.log("A dog!");
11228+ return;
11229+ }
11230+ console.log("Not a dog...");
11231+}
11232+
11233+export { person1, message, myStatus, isPet };
11234+```
11235+
11236+</CodeTab>
11237+
11238+### Match on Exceptions
11239+
11240+If the function throws an exception (covered later), you can also match on _that_, in addition to the function's normally returned values.
11241+
11242+<CodeTab labels={["ReScript", "JS Output"]}>
11243+
11244+```res nocheck
11245+switch List.find(i => i === theItem, myItems) {
11246+| item => Console.log(item)
11247+| exception Not_found => Console.log("No such item found!")
11248+}
11249+```
11250+
11251+```js
11252+var exit = 0;
11253+
11254+var item;
11255+
11256+try {
11257+ item = List.find(function (i) {
11258+ return i === theItem;
11259+ }, myItems);
11260+ exit = 1;
11261+} catch (raw_exn) {
11262+ var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
11263+ if (exn.RE_EXN_ID === "Not_found") {
11264+ console.log("No such item found!");
11265+ } else {
11266+ throw exn;
11267+ }
11268+}
11269+
11270+if (exit === 1) {
11271+ console.log(item);
11272+}
11273+```
11274+
11275+</CodeTab>
11276+
11277+### Match on Array
11278+
11279+<CodeTab labels={["ReScript", "JS Output"]}>
11280+
11281+```res
11282+let students = ["Jane", "Harvey", "Patrick"]
11283+switch students {
11284+| [] => Console.log("There are no students")
11285+| [student1] =>
11286+ Console.log("There's a single student here: " ++ student1)
11287+| manyStudents =>
11288+ // display the array of names
11289+ Console.log2("The students are: ", manyStudents)
11290+}
11291+```
11292+
11293+```js
11294+let person1 = {
11295+ TAG: "Teacher",
11296+ name: "Jane",
11297+ age: 35,
11298+};
11299+
11300+let message;
11301+
11302+if (person1.TAG === "Teacher") {
11303+ message = `Hello ` + "Jane" + `.`;
11304+} else {
11305+ let match = "Jane";
11306+ let match$1 = match.status;
11307+ let name = match.name;
11308+ let match$2 = match.reportCard;
11309+ if (match$2.passing) {
11310+ message =
11311+ `Congrats ` +
11312+ name +
11313+ `, nice GPA of ` +
11314+ match$2.gpa.toString() +
11315+ ` you got there!`;
11316+ } else {
11317+ let exit = 0;
11318+ if (typeof match$1 !== "object") {
11319+ message =
11320+ match$1 === "Sick"
11321+ ? `How are you feeling?`
11322+ : `Good luck next semester ` + name + `!`;
11323+ } else {
11324+ exit = 1;
11325+ }
11326+ if (exit === 1) {
11327+ message =
11328+ match.reportCard.gpa !== 0.0
11329+ ? `Good luck next semester ` + name + `!`
11330+ : `Come back in ` + match$1._0.toString() + ` days!`;
11331+ }
11332+ }
11333+}
11334+
11335+let myStatus = {
11336+ TAG: "Vacations",
11337+ _0: 10,
11338+};
11339+
11340+let exit$1 = 0;
11341+
11342+if (typeof myStatus !== "object") {
11343+ console.log("Hey! How are you?");
11344+} else {
11345+ exit$1 = 1;
11346+}
11347+
11348+if (exit$1 === 1) {
11349+ console.log(`Come back in ` + (10).toString() + ` days!`);
11350+}
11351+
11352+let students = ["Jane", "Harvey", "Patrick"];
11353+
11354+let len = students.length;
11355+
11356+if (len !== 1) {
11357+ if (len !== 0) {
11358+ console.log("The students are: ", students);
11359+ } else {
11360+ console.log("There are no students");
11361+ }
11362+} else {
11363+ let student1 = students[0];
11364+ console.log("There's a single student here: " + student1);
11365+}
11366+
11367+export { person1, message, myStatus, students };
11368+```
11369+
11370+</CodeTab>
11371+
11372+### Match on List
11373+
11374+Pattern matching on list is similar to array, but with the extra feature of extracting the tail of a list (all elements except the first one):
11375+
11376+<CodeTab labels={["ReScript", "JS Output"]}>
11377+
11378+```res
11379+let rec printStudents = (students) => {
11380+ switch students {
11381+ | list{} => () // done
11382+ | list{student} => Console.log("Last student: " ++ student)
11383+ | list{student1, ...otherStudents} =>
11384+ Console.log(student1)
11385+ printStudents(otherStudents)
11386+ }
11387+}
11388+printStudents(list{"Jane", "Harvey", "Patrick"})
11389+```
11390+
11391+```js
11392+let person1 = {
11393+ TAG: "Teacher",
11394+ name: "Jane",
11395+ age: 35,
11396+};
11397+
11398+let message;
11399+
11400+if (person1.TAG === "Teacher") {
11401+ message = `Hello ` + "Jane" + `.`;
11402+} else {
11403+ let match = "Jane";
11404+ let match$1 = match.status;
11405+ let name = match.name;
11406+ let match$2 = match.reportCard;
11407+ if (match$2.passing) {
11408+ message =
11409+ `Congrats ` +
11410+ name +
11411+ `, nice GPA of ` +
11412+ match$2.gpa.toString() +
11413+ ` you got there!`;
11414+ } else {
11415+ let exit = 0;
11416+ if (typeof match$1 !== "object") {
11417+ message =
11418+ match$1 === "Sick"
11419+ ? `How are you feeling?`
11420+ : `Good luck next semester ` + name + `!`;
11421+ } else {
11422+ exit = 1;
11423+ }
11424+ if (exit === 1) {
11425+ message =
11426+ match.reportCard.gpa !== 0.0
11427+ ? `Good luck next semester ` + name + `!`
11428+ : `Come back in ` + match$1._0.toString() + ` days!`;
11429+ }
11430+ }
11431+}
11432+
11433+let myStatus = {
11434+ TAG: "Vacations",
11435+ _0: 10,
11436+};
11437+
11438+let exit$1 = 0;
11439+
11440+if (typeof myStatus !== "object") {
11441+ console.log("Hey! How are you?");
11442+} else {
11443+ exit$1 = 1;
11444+}
11445+
11446+if (exit$1 === 1) {
11447+ console.log(`Come back in ` + (10).toString() + ` days!`);
11448+}
11449+
11450+function printStudents(_students) {
11451+ while (true) {
11452+ let students = _students;
11453+ if (students === 0) {
11454+ return;
11455+ }
11456+ let otherStudents = students.tl;
11457+ let student = students.hd;
11458+ if (otherStudents !== 0) {
11459+ console.log(student);
11460+ _students = otherStudents;
11461+ continue;
11462+ }
11463+ console.log("Last student: " + student);
11464+ return;
11465+ }
11466+}
11467+
11468+printStudents({
11469+ hd: "Jane",
11470+ tl: {
11471+ hd: "Harvey",
11472+ tl: {
11473+ hd: "Patrick",
11474+ tl: /* [] */ 0,
11475+ },
11476+ },
11477+});
11478+
11479+export { person1, message, myStatus, printStudents };
11480+```
11481+
11482+</CodeTab>
11483+
11484+### Match on Dictionaries
11485+
11486+You can pattern match on dictionaries just like you can on other ReScript data structures.
11487+
11488+When pattern matching on a dictionary it's assumed by default that you're expecting the keys you match on to exist in the dictionary. Example:
11489+
11490+<CodeTab labels={["ReScript", "JS Output"]}>
11491+
11492+```res prelude
11493+let d = dict{"A": 5, "B": 6}
11494+
11495+// We're expecting the `B` key to exist below, and `b` will be `int` in the match branch
11496+let b = switch d {
11497+| dict{"B": b} => Some(b)
11498+| _ => None
11499+}
11500+```
11501+
11502+```js
11503+let d = {
11504+ A: 5,
11505+ B: 6,
11506+};
11507+
11508+let b = d.B;
11509+
11510+let b$1 = b !== undefined ? b : undefined;
11511+```
11512+
11513+</CodeTab>
11514+
11515+However, there are situations where you want to pull out the value of a key as an option. You can do that using the `?` optional syntax in the pattern match:
11516+
11517+<CodeTab labels={["ReScript", "JS Output"]}>
11518+
11519+```res prelude
11520+let d = dict{"A": 5, "B": 6}
11521+
11522+// We're pulling out `B` regardless of if it has a value or not, and therefore get `b` as `option<int>`
11523+let b = switch d {
11524+| dict{"B": ?b} => b
11525+}
11526+```
11527+
11528+```js
11529+let d = {
11530+ A: 5,
11531+ B: 6,
11532+};
11533+
11534+let b = d.B;
11535+```
11536+
11537+</CodeTab>
11538+
11539+Notice how in the first case, when not using `?`, we had to supply a catch-all case `_`. That's because the pattern match _expects_ `B` to exist in the first case, for the pattern to match. If `B` doesn't exist, the match falls through to the next branch, and therefore we need to catch it to be exhaustive in our matching.
11540+
11541+However, in the second case, we don't need a catch-all case. That's because the first branch will _always_ match the dictionary - either `B` exists or it doesn't, but it doesn't matter because we're pulling it out as an optional value.
11542+
11543+### Small Pitfall
11544+
11545+**Note**: you can only pass literals (i.e. concrete values) as a pattern, not let-binding names or other things. The following doesn't work as expected:
11546+
11547+<CodeTab labels={["ReScript", "JS Output"]}>
11548+
11549+```res
11550+let coordinates = (10, 20, 30)
11551+let centerY = 20
11552+switch coordinates {
11553+| (x, _centerY, _) => Console.log(x)
11554+}
11555+```
11556+
11557+```js
11558+let person1 = {
11559+ TAG: "Teacher",
11560+ name: "Jane",
11561+ age: 35,
11562+};
11563+
11564+let message;
11565+
11566+if (person1.TAG === "Teacher") {
11567+ message = `Hello ` + "Jane" + `.`;
11568+} else {
11569+ let match = "Jane";
11570+ let match$1 = match.status;
11571+ let name = match.name;
11572+ let match$2 = match.reportCard;
11573+ if (match$2.passing) {
11574+ message =
11575+ `Congrats ` +
11576+ name +
11577+ `, nice GPA of ` +
11578+ match$2.gpa.toString() +
11579+ ` you got there!`;
11580+ } else {
11581+ let exit = 0;
11582+ if (typeof match$1 !== "object") {
11583+ message =
11584+ match$1 === "Sick"
11585+ ? `How are you feeling?`
11586+ : `Good luck next semester ` + name + `!`;
11587+ } else {
11588+ exit = 1;
11589+ }
11590+ if (exit === 1) {
11591+ message =
11592+ match.reportCard.gpa !== 0.0
11593+ ? `Good luck next semester ` + name + `!`
11594+ : `Come back in ` + match$1._0.toString() + ` days!`;
11595+ }
11596+ }
11597+}
11598+
11599+let myStatus = {
11600+ TAG: "Vacations",
11601+ _0: 10,
11602+};
11603+
11604+let exit$1 = 0;
11605+
11606+if (typeof myStatus !== "object") {
11607+ console.log("Hey! How are you?");
11608+} else {
11609+ exit$1 = 1;
11610+}
11611+
11612+if (exit$1 === 1) {
11613+ console.log(`Come back in ` + (10).toString() + ` days!`);
11614+}
11615+
11616+let d = {
11617+ A: 5,
11618+ B: 6,
11619+};
11620+
11621+console.log(10);
11622+
11623+let b = d.B;
11624+
11625+let coordinates = [10, 20, 30];
11626+
11627+let centerY = 20;
11628+
11629+export { person1, message, myStatus, d, b, coordinates, centerY };
11630+```
11631+
11632+</CodeTab>
11633+
11634+A first time ReScript user might accidentally write that code, assuming that it's matching on `coordinates` when the second value is of the same value as `centerY`. In reality, this is interpreted as matching on coordinates and assigning the second value of the tuple to the name `centerY`, which isn't what's intended.
11635+
11636+## Exhaustiveness Check
11637+
11638+As if the above features aren't enough, ReScript also provides arguably the most important pattern matching feature: **compile-time check of missing patterns**.
11639+
11640+Let's revisit one of the above examples:
11641+
11642+<CodeTab labels={["ReScript", "JS Output"]}>
11643+
11644+```res nocheck
11645+let message = switch person1 {
11646+| Teacher({name: "Mary" | "Joe"}) =>
11647+ `Hey, still going to the party on Saturday?`
11648+| Student({name, reportCard: {passing: true, gpa}}) =>
11649+ `Congrats ${name}, nice GPA of ${Float.toString(gpa)} you got there!`
11650+| Student({
11651+ reportCard: {gpa: 0.0},
11652+ status: Vacations(daysLeft) | Sabbatical(daysLeft)
11653+ }) =>
11654+ `Come back in ${Int.toString(daysLeft)} days!`
11655+| Student({status: Sick}) =>
11656+ `How are you feeling?`
11657+| Student({name}) =>
11658+ `Good luck next semester ${name}!`
11659+}
11660+```
11661+
11662+```js
11663+if (person1.TAG) {
11664+ var match$1 = person1.status;
11665+ var name = person1.name;
11666+ var match$2 = person1.reportCard;
11667+ if (match$2.passing) {
11668+ "Congrats " +
11669+ name +
11670+ ", nice GPA of " +
11671+ match$2.gpa.toString() +
11672+ " you got there!";
11673+ } else if (typeof match$1 === "number") {
11674+ if (match$1 !== 0) {
11675+ "Good luck next semester " + name + "!";
11676+ } else {
11677+ ("How are you feeling?");
11678+ }
11679+ } else if (person1.reportCard.gpa !== 0.0) {
11680+ "Good luck next semester " + name + "!";
11681+ } else {
11682+ "Come back in " + match$1._0.toString() + " days!";
11683+ }
11684+} else {
11685+ switch (person1.name) {
11686+ case "Joe":
11687+ case "Mary":
11688+ break;
11689+ default:
11690+ throw {
11691+ RE_EXN_ID: "Match_failure",
11692+ _1: ["playground.res", 13, 0],
11693+ Error: new Error(),
11694+ };
11695+ }
11696+}
11697+```
11698+
11699+</CodeTab>
11700+
11701+Did you see what we removed? This time, we've omitted the handling of the case where `person1` is `Teacher({name})` when `name` isn't Mary or Joe.
11702+
11703+Failing to handle every scenario of a value likely constitutes the majority of program bugs out there. This happens very often when you refactor a piece of code someone else wrote. Fortunately for ReScript, the compiler will tell you so:
11704+
11705+```
11706+Warning 8: this pattern-matching is not exhaustive.
11707+Here is an example of a value that is not matched:
11708+Some({name: ""})
11709+```
11710+
11711+**BAM**! You've just erased an entire category of important bugs before you even ran the code. In fact, this is how most of nullable values is handled:
11712+
11713+<CodeTab labels={["ReScript", "JS Output"]}>
11714+
11715+```res
11716+let myNullableValue = Some(5)
11717+
11718+switch myNullableValue {
11719+| Some(_v) => Console.log("value is present")
11720+| None => Console.log("value is absent")
11721+}
11722+```
11723+
11724+```js
11725+let person1 = {
11726+ TAG: "Teacher",
11727+ name: "Jane",
11728+ age: 35,
11729+};
11730+
11731+let message;
11732+
11733+if (person1.TAG === "Teacher") {
11734+ message = `Hello ` + "Jane" + `.`;
11735+} else {
11736+ let match = "Jane";
11737+ let match$1 = match.status;
11738+ let name = match.name;
11739+ let match$2 = match.reportCard;
11740+ if (match$2.passing) {
11741+ message =
11742+ `Congrats ` +
11743+ name +
11744+ `, nice GPA of ` +
11745+ match$2.gpa.toString() +
11746+ ` you got there!`;
11747+ } else {
11748+ let exit = 0;
11749+ if (typeof match$1 !== "object") {
11750+ message =
11751+ match$1 === "Sick"
11752+ ? `How are you feeling?`
11753+ : `Good luck next semester ` + name + `!`;
11754+ } else {
11755+ exit = 1;
11756+ }
11757+ if (exit === 1) {
11758+ message =
11759+ match.reportCard.gpa !== 0.0
11760+ ? `Good luck next semester ` + name + `!`
11761+ : `Come back in ` + match$1._0.toString() + ` days!`;
11762+ }
11763+ }
11764+}
11765+
11766+let myStatus = {
11767+ TAG: "Vacations",
11768+ _0: 10,
11769+};
11770+
11771+let exit$1 = 0;
11772+
11773+if (typeof myStatus !== "object") {
11774+ console.log("Hey! How are you?");
11775+} else {
11776+ exit$1 = 1;
11777+}
11778+
11779+if (exit$1 === 1) {
11780+ console.log(`Come back in ` + (10).toString() + ` days!`);
11781+}
11782+
11783+let d = {
11784+ A: 5,
11785+ B: 6,
11786+};
11787+
11788+console.log("value is present");
11789+
11790+let b = d.B;
11791+
11792+let myNullableValue = 5;
11793+
11794+export { person1, message, myStatus, d, b, myNullableValue };
11795+```
11796+
11797+</CodeTab>
11798+
11799+If you don't handle the `None` case, the compiler warns. No more `undefined` bugs in your code!
11800+
11801+## Conclusion & Tips & Tricks
11802+
11803+Hopefully you can see how pattern matching is a game changer for writing correct code, through the concise destructuring syntax, the proper conditions handling of `switch`, and the static exhaustiveness check.
11804+
11805+Below is some advice:
11806+
11807+Avoid using the wildcard `_` unnecessarily. Using the wildcard `_` will bypass the compiler's exhaustiveness check. Consequently, the compiler will not be able to notify you of probable errors when you add a new case to a variant. Try only using `_` against infinite possibilities, e.g. string, int, etc.
11808+
11809+Use the `if` clause sparingly.
11810+
11811+**Flatten your pattern-match whenever you can**. This is a real bug remover. Here's a series of examples, from worst to best:
11812+
11813+<CodeTab labels={["ReScript", "JS Output"]}>
11814+
11815+```res
11816+let optionBoolToBool = opt => {
11817+ if opt == None {
11818+ false
11819+ } else if opt === Some(true) {
11820+ true
11821+ } else {
11822+ false
11823+ }
11824+}
11825+```
11826+
11827+```js
11828+let person1 = {
11829+ TAG: "Teacher",
11830+ name: "Jane",
11831+ age: 35,
11832+};
11833+
11834+let message;
11835+
11836+if (person1.TAG === "Teacher") {
11837+ message = `Hello ` + "Jane" + `.`;
11838+} else {
11839+ let match = "Jane";
11840+ let match$1 = match.status;
11841+ let name = match.name;
11842+ let match$2 = match.reportCard;
11843+ if (match$2.passing) {
11844+ message =
11845+ `Congrats ` +
11846+ name +
11847+ `, nice GPA of ` +
11848+ match$2.gpa.toString() +
11849+ ` you got there!`;
11850+ } else {
11851+ let exit = 0;
11852+ if (typeof match$1 !== "object") {
11853+ message =
11854+ match$1 === "Sick"
11855+ ? `How are you feeling?`
11856+ : `Good luck next semester ` + name + `!`;
11857+ } else {
11858+ exit = 1;
11859+ }
11860+ if (exit === 1) {
11861+ message =
11862+ match.reportCard.gpa !== 0.0
11863+ ? `Good luck next semester ` + name + `!`
11864+ : `Come back in ` + match$1._0.toString() + ` days!`;
11865+ }
11866+ }
11867+}
11868+
11869+let myStatus = {
11870+ TAG: "Vacations",
11871+ _0: 10,
11872+};
11873+
11874+let exit$1 = 0;
11875+
11876+if (typeof myStatus !== "object") {
11877+ console.log("Hey! How are you?");
11878+} else {
11879+ exit$1 = 1;
11880+}
11881+
11882+if (exit$1 === 1) {
11883+ console.log(`Come back in ` + (10).toString() + ` days!`);
11884+}
11885+
11886+let d = {
11887+ A: 5,
11888+ B: 6,
11889+};
11890+
11891+function optionBoolToBool(opt) {
11892+ if (opt === undefined) {
11893+ return false;
11894+ } else {
11895+ return opt === true;
11896+ }
11897+}
11898+
11899+let b = d.B;
11900+
11901+export { person1, message, myStatus, d, b, optionBoolToBool };
11902+```
11903+
11904+</CodeTab>
11905+
11906+Now that's just silly =). Let's turn it into pattern-matching:
11907+
11908+<CodeTab labels={["ReScript", "JS Output"]}>
11909+
11910+```res
11911+let optionBoolToBool = opt => {
11912+ switch opt {
11913+ | None => false
11914+ | Some(a) => a ? true : false
11915+ }
11916+}
11917+```
11918+
11919+```js
11920+let person1 = {
11921+ TAG: "Teacher",
11922+ name: "Jane",
11923+ age: 35,
11924+};
11925+
11926+let message;
11927+
11928+if (person1.TAG === "Teacher") {
11929+ message = `Hello ` + "Jane" + `.`;
11930+} else {
11931+ let match = "Jane";
11932+ let match$1 = match.status;
11933+ let name = match.name;
11934+ let match$2 = match.reportCard;
11935+ if (match$2.passing) {
11936+ message =
11937+ `Congrats ` +
11938+ name +
11939+ `, nice GPA of ` +
11940+ match$2.gpa.toString() +
11941+ ` you got there!`;
11942+ } else {
11943+ let exit = 0;
11944+ if (typeof match$1 !== "object") {
11945+ message =
11946+ match$1 === "Sick"
11947+ ? `How are you feeling?`
11948+ : `Good luck next semester ` + name + `!`;
11949+ } else {
11950+ exit = 1;
11951+ }
11952+ if (exit === 1) {
11953+ message =
11954+ match.reportCard.gpa !== 0.0
11955+ ? `Good luck next semester ` + name + `!`
11956+ : `Come back in ` + match$1._0.toString() + ` days!`;
11957+ }
11958+ }
11959+}
11960+
11961+let myStatus = {
11962+ TAG: "Vacations",
11963+ _0: 10,
11964+};
11965+
11966+let exit$1 = 0;
11967+
11968+if (typeof myStatus !== "object") {
11969+ console.log("Hey! How are you?");
11970+} else {
11971+ exit$1 = 1;
11972+}
11973+
11974+if (exit$1 === 1) {
11975+ console.log(`Come back in ` + (10).toString() + ` days!`);
11976+}
11977+
11978+let d = {
11979+ A: 5,
11980+ B: 6,
11981+};
11982+
11983+function optionBoolToBool(opt) {
11984+ if (opt !== undefined) {
11985+ return opt;
11986+ } else {
11987+ return false;
11988+ }
11989+}
11990+
11991+let b = d.B;
11992+
11993+export { person1, message, myStatus, d, b, optionBoolToBool };
11994+```
11995+
11996+</CodeTab>
11997+
11998+Slightly better, but still nested. Pattern-matching allows you to do this:
11999+
12000+<CodeTab labels={["ReScript", "JS Output"]}>
12001+
12002+```res
12003+let optionBoolToBool = opt => {
12004+ switch opt {
12005+ | None => false
12006+ | Some(true) => true
12007+ | Some(false) => false
12008+ }
12009+}
12010+```
12011+
12012+```js
12013+let person1 = {
12014+ TAG: "Teacher",
12015+ name: "Jane",
12016+ age: 35,
12017+};
12018+
12019+let message;
12020+
12021+if (person1.TAG === "Teacher") {
12022+ message = `Hello ` + "Jane" + `.`;
12023+} else {
12024+ let match = "Jane";
12025+ let match$1 = match.status;
12026+ let name = match.name;
12027+ let match$2 = match.reportCard;
12028+ if (match$2.passing) {
12029+ message =
12030+ `Congrats ` +
12031+ name +
12032+ `, nice GPA of ` +
12033+ match$2.gpa.toString() +
12034+ ` you got there!`;
12035+ } else {
12036+ let exit = 0;
12037+ if (typeof match$1 !== "object") {
12038+ message =
12039+ match$1 === "Sick"
12040+ ? `How are you feeling?`
12041+ : `Good luck next semester ` + name + `!`;
12042+ } else {
12043+ exit = 1;
12044+ }
12045+ if (exit === 1) {
12046+ message =
12047+ match.reportCard.gpa !== 0.0
12048+ ? `Good luck next semester ` + name + `!`
12049+ : `Come back in ` + match$1._0.toString() + ` days!`;
12050+ }
12051+ }
12052+}
12053+
12054+let myStatus = {
12055+ TAG: "Vacations",
12056+ _0: 10,
12057+};
12058+
12059+let exit$1 = 0;
12060+
12061+if (typeof myStatus !== "object") {
12062+ console.log("Hey! How are you?");
12063+} else {
12064+ exit$1 = 1;
12065+}
12066+
12067+if (exit$1 === 1) {
12068+ console.log(`Come back in ` + (10).toString() + ` days!`);
12069+}
12070+
12071+let d = {
12072+ A: 5,
12073+ B: 6,
12074+};
12075+
12076+function optionBoolToBool(opt) {
12077+ if (opt !== undefined) {
12078+ return opt;
12079+ } else {
12080+ return false;
12081+ }
12082+}
12083+
12084+let b = d.B;
12085+
12086+export { person1, message, myStatus, d, b, optionBoolToBool };
12087+```
12088+
12089+</CodeTab>
12090+
12091+Much more linear-looking! Now, you might be tempted to do this:
12092+
12093+<CodeTab labels={["ReScript", "JS Output"]}>
12094+
12095+```res
12096+let optionBoolToBool = opt => {
12097+ switch opt {
12098+ | Some(true) => true
12099+ | _ => false
12100+ }
12101+}
12102+```
12103+
12104+```js
12105+let person1 = {
12106+ TAG: "Teacher",
12107+ name: "Jane",
12108+ age: 35,
12109+};
12110+
12111+let message;
12112+
12113+if (person1.TAG === "Teacher") {
12114+ message = `Hello ` + "Jane" + `.`;
12115+} else {
12116+ let match = "Jane";
12117+ let match$1 = match.status;
12118+ let name = match.name;
12119+ let match$2 = match.reportCard;
12120+ if (match$2.passing) {
12121+ message =
12122+ `Congrats ` +
12123+ name +
12124+ `, nice GPA of ` +
12125+ match$2.gpa.toString() +
12126+ ` you got there!`;
12127+ } else {
12128+ let exit = 0;
12129+ if (typeof match$1 !== "object") {
12130+ message =
12131+ match$1 === "Sick"
12132+ ? `How are you feeling?`
12133+ : `Good luck next semester ` + name + `!`;
12134+ } else {
12135+ exit = 1;
12136+ }
12137+ if (exit === 1) {
12138+ message =
12139+ match.reportCard.gpa !== 0.0
12140+ ? `Good luck next semester ` + name + `!`
12141+ : `Come back in ` + match$1._0.toString() + ` days!`;
12142+ }
12143+ }
12144+}
12145+
12146+let myStatus = {
12147+ TAG: "Vacations",
12148+ _0: 10,
12149+};
12150+
12151+let exit$1 = 0;
12152+
12153+if (typeof myStatus !== "object") {
12154+ console.log("Hey! How are you?");
12155+} else {
12156+ exit$1 = 1;
12157+}
12158+
12159+if (exit$1 === 1) {
12160+ console.log(`Come back in ` + (10).toString() + ` days!`);
12161+}
12162+
12163+let d = {
12164+ A: 5,
12165+ B: 6,
12166+};
12167+
12168+function optionBoolToBool(opt) {
12169+ if (opt !== undefined) {
12170+ return opt;
12171+ } else {
12172+ return false;
12173+ }
12174+}
12175+
12176+let b = d.B;
12177+
12178+export { person1, message, myStatus, d, b, optionBoolToBool };
12179+```
12180+
12181+</CodeTab>
12182+
12183+Which is much more concise, but kills the exhaustiveness check mentioned above; refrain from using that. This is the best:
12184+
12185+<CodeTab labels={["ReScript", "JS Output"]}>
12186+
12187+```res
12188+let optionBoolToBool = opt => {
12189+ switch opt {
12190+ | Some(trueOrFalse) => trueOrFalse
12191+ | None => false
12192+ }
12193+}
12194+```
12195+
12196+```js
12197+let person1 = {
12198+ TAG: "Teacher",
12199+ name: "Jane",
12200+ age: 35,
12201+};
12202+
12203+let message;
12204+
12205+if (person1.TAG === "Teacher") {
12206+ message = `Hello ` + "Jane" + `.`;
12207+} else {
12208+ let match = "Jane";
12209+ let match$1 = match.status;
12210+ let name = match.name;
12211+ let match$2 = match.reportCard;
12212+ if (match$2.passing) {
12213+ message =
12214+ `Congrats ` +
12215+ name +
12216+ `, nice GPA of ` +
12217+ match$2.gpa.toString() +
12218+ ` you got there!`;
12219+ } else {
12220+ let exit = 0;
12221+ if (typeof match$1 !== "object") {
12222+ message =
12223+ match$1 === "Sick"
12224+ ? `How are you feeling?`
12225+ : `Good luck next semester ` + name + `!`;
12226+ } else {
12227+ exit = 1;
12228+ }
12229+ if (exit === 1) {
12230+ message =
12231+ match.reportCard.gpa !== 0.0
12232+ ? `Good luck next semester ` + name + `!`
12233+ : `Come back in ` + match$1._0.toString() + ` days!`;
12234+ }
12235+ }
12236+}
12237+
12238+let myStatus = {
12239+ TAG: "Vacations",
12240+ _0: 10,
12241+};
12242+
12243+let exit$1 = 0;
12244+
12245+if (typeof myStatus !== "object") {
12246+ console.log("Hey! How are you?");
12247+} else {
12248+ exit$1 = 1;
12249+}
12250+
12251+if (exit$1 === 1) {
12252+ console.log(`Come back in ` + (10).toString() + ` days!`);
12253+}
12254+
12255+let d = {
12256+ A: 5,
12257+ B: 6,
12258+};
12259+
12260+function optionBoolToBool(opt) {
12261+ if (opt !== undefined) {
12262+ return opt;
12263+ } else {
12264+ return false;
12265+ }
12266+}
12267+
12268+let b = d.B;
12269+
12270+export { person1, message, myStatus, d, b, optionBoolToBool };
12271+```
12272+
12273+</CodeTab>
12274+
12275+Pretty darn hard to make a mistake in this code at this point! Whenever you'd like to use an if-else with many branches, prefer pattern matching instead. It's more concise and [performant](./variant.mdx#design-decisions) too.
12276+
12277+---
12278+title: "Pipe"
12279+description: "The Pipe operator (->)"
12280+canonical: "/docs/manual/pipe"
12281+section: "Language Features"
12282+order: 15
12283+---
12284+
12285+# Pipe
12286+
12287+ReScript provides a tiny but surprisingly useful operator `->`, called the "pipe", that allows you to "flip" your code inside-out. `a(b)` becomes `b->a`. It's a simple piece of syntax that doesn't have any runtime cost.
12288+
12289+Why would you use it? Imagine you have the following:
12290+
12291+<CodeTab labels={["ReScript", "JS Output"]}>
12292+
12293+```res nocheck
12294+validateAge(getAge(parseData(person)))
12295+```
12296+
12297+```js
12298+validateAge(getAge(parseData(person)));
12299+```
12300+
12301+</CodeTab>
12302+
12303+This is slightly hard to read, since you need to read the code from the innermost part, to the outer parts. Use pipe to streamline it:
12304+
12305+<CodeTab labels={["ReScript", "JS Output"]}>
12306+
12307+```res nocheck
12308+person
12309+ ->parseData
12310+ ->getAge
12311+ ->validateAge
12312+```
12313+
12314+```js
12315+validateAge(getAge(parseData(person)));
12316+```
12317+
12318+</CodeTab>
12319+
12320+Basically, `parseData(person)` is transformed into `person->parseData`, and `getAge(person->parseData)` is transformed into `person->parseData->getAge`, etc.
12321+
12322+**This works when the function takes more than one argument too**.
12323+
12324+<CodeTab labels={["ReScript", "JS Output"]}>
12325+
12326+```res nocheck
12327+a(one, two, three)
12328+```
12329+
12330+```js
12331+a(one, two, three);
12332+```
12333+
12334+</CodeTab>
12335+
12336+is the same as
12337+
12338+<CodeTab labels={["ReScript", "JS Output"]}>
12339+
12340+```res nocheck
12341+one->a(two, three)
12342+```
12343+
12344+```js
12345+a(one, two, three);
12346+```
12347+
12348+</CodeTab>
12349+
12350+This also works with labeled arguments.
12351+
12352+Pipes are used to emulate object-oriented programming. For example, `myStudent.getName` in other languages like Java would be `myStudent->getName` in ReScript (equivalent to `getName(myStudent)`). This allows us to have the readability of OOP without the downside of dragging in a huge class system just to call a function on a piece of data.
12353+
12354+## Tips & Tricks
12355+
12356+Do **not** abuse pipes; they're a means to an end. Inexperienced engineers sometimes shape a library's API to take advantage of the pipe. This is backwards.
12357+
12358+## JS Method Chaining
12359+
12360+[bind to JS function](./bind-to-js-function.mdx) docs
12361+
12362+JavaScript's APIs are often attached to objects, and are often chainable, like so:
12363+
12364+```js
12365+const result = [1, 2, 3].map((a) => a + 1).filter((a) => a % 2 === 0);
12366+
12367+asyncRequest().setWaitDuration(4000).send();
12368+```
12369+
12370+Assuming we don't need the chaining behavior above, we'd bind to each case of this using [`@send`](../../syntax-lookup/decorator_send.mdx) from the aforementioned binding API page:
12371+
12372+<CodeTab labels={["ReScript", "JS Output"]}>
12373+
12374+```res prelude
12375+type request
12376+@val external asyncRequest: unit => request = "asyncRequest"
12377+@send external setWaitDuration: (request, int) => request = "setWaitDuration"
12378+@send external send: request => unit = "send"
12379+```
12380+
12381+```js
12382+// Empty output
12383+```
12384+
12385+</CodeTab>
12386+
12387+You'd use them like this:
12388+
12389+<CodeTab labels={["ReScript", "JS Output"]}>
12390+
12391+```res nocheck
12392+let result = Array.filter(
12393+ Array.map([1, 2, 3], a => a + 1),
12394+ a => mod(a, 2) == 0
12395+)
12396+
12397+send(setWaitDuration(asyncRequest(), 4000))
12398+```
12399+
12400+```js
12401+let result = [1, 2, 3].map((a) => (a + 1) | 0).filter((a) => a % 2 === 0);
12402+
12403+asyncRequest().setWaitDuration(4000).send();
12404+
12405+export { result };
12406+```
12407+
12408+</CodeTab>
12409+
12410+This looks much worse than the JS counterpart! Clean it up visually with pipe:
12411+
12412+<CodeTab labels={["ReScript", "JS Output"]}>
12413+
12414+```res nocheck
12415+let result = [1, 2, 3]
12416+ ->Array.map(a => a + 1)
12417+ ->Array.filter(a => mod(a, 2) == 0)
12418+
12419+asyncRequest()->setWaitDuration(4000)->send
12420+```
12421+
12422+```js
12423+let result = [1, 2, 3].map((a) => (a + 1) | 0).filter((a) => a % 2 === 0);
12424+
12425+asyncRequest().setWaitDuration(4000).send();
12426+
12427+export { result };
12428+```
12429+
12430+</CodeTab>
12431+
12432+## Pipe Into Variants
12433+
12434+You can pipe into a variant's constructor as if it was a function:
12435+
12436+<CodeTab labels={["ReScript", "JS Output"]}>
12437+
12438+```res nocheck
12439+let result = name->preprocess->Some
12440+```
12441+
12442+```js
12443+var result = preprocess(name);
12444+```
12445+
12446+</CodeTab>
12447+
12448+We turn this into:
12449+
12450+<CodeTab labels={["ReScript", "JS Output"]}>
12451+
12452+```res nocheck
12453+let result = Some(preprocess(name))
12454+```
12455+
12456+```js
12457+var result = preprocess(name);
12458+```
12459+
12460+</CodeTab>
12461+
12462+**Note** that using a variant constructor as a function wouldn't work anywhere else beside here.
12463+
12464+## Pipe Placeholders
12465+
12466+A placeholder is written as an underscore and it tells ReScript that you want to fill in an argument of a function later. These two have equivalent meaning:
12467+
12468+```res nocheck
12469+let addTo7 = (x) => add3(3, x, 4)
12470+let addTo7 = add3(3, _, 4)
12471+```
12472+
12473+Sometimes you don't want to pipe the value you have into the first position. In these cases you can mark a placeholder value to show which argument you would like to pipe into.
12474+
12475+Let's say you have a function `namePerson`, which takes a `person` then a `name` argument. If you are transforming a person then pipe will work as-is:
12476+
12477+<CodeTab labels={["ReScript", "JS Output"]}>
12478+
12479+```res nocheck
12480+makePerson(~age=47)
12481+ ->namePerson("Jane")
12482+```
12483+
12484+```js
12485+namePerson(makePerson(47), "Jane");
12486+```
12487+
12488+</CodeTab>
12489+
12490+If you have a name that you want to apply to a person object, you can use a placeholder:
12491+
12492+<CodeTab labels={["ReScript", "JS Output"]}>
12493+
12494+```res nocheck
12495+getName(input)
12496+ ->namePerson(personDetails, _)
12497+```
12498+
12499+```js
12500+var __x = getName(input);
12501+namePerson(personDetails, __x);
12502+```
12503+
12504+</CodeTab>
12505+
12506+This allows you to pipe into any positional argument. It also works for named arguments:
12507+
12508+<CodeTab labels={["ReScript", "JS Output"]}>
12509+
12510+```res nocheck
12511+getName(input)
12512+ ->namePerson(~person=personDetails, ~name=_)
12513+```
12514+
12515+```js
12516+var __x = getName(input);
12517+namePerson(personDetails, __x);
12518+```
12519+
12520+</CodeTab>
12521+
12522+---
12523+title: "Polymorphic Variant"
12524+description: "The Polymorphic Variant data structure in ReScript"
12525+canonical: "/docs/manual/polymorphic-variant"
12526+section: "Language Features"
12527+order: 10
12528+---
12529+
12530+# Polymorphic Variant
12531+
12532+Polymorphic variants (or poly variant) are a cousin of [variant](./variant.mdx). With these differences:
12533+
12534+- They start with a `#` and the constructor name doesn't need to be capitalized.
12535+- They don't require an explicit type definition. The type is inferred from usage.
12536+- Values of different poly variant types can share the constructors they have in common (aka, poly variants are "structurally" typed, as opposed to ["nominally" typed](./variant.mdx#variant-types-are-found-by-field-name)).
12537+
12538+They're a convenient and useful alternative to regular variants, but should **not** be abused. See the drawbacks at the end of this page.
12539+
12540+## Creation
12541+
12542+We provide 3 syntaxes for a poly variant's constructor:
12543+
12544+<CodeTab labels={["ReScript", "JS Output"]}>
12545+
12546+```res
12547+let myColor = #red
12548+let myLabel = #"aria-hidden"
12549+let myNumber = #7
12550+```
12551+
12552+```js
12553+let myColor = "red";
12554+
12555+let myLabel = "aria-hidden";
12556+
12557+let myNumber = 7;
12558+
12559+export { myColor, myLabel, myNumber };
12560+```
12561+
12562+</CodeTab>
12563+
12564+**Take a look at the output**. Poly variants are _great_ for JavaScript interop. For example, you can use it to model JavaScript string and number enums like TypeScript, but without confusing their accidental usage with regular strings and numbers.
12565+
12566+`myColor` uses the common syntax. The second and third syntaxes are to support expressing strings and numbers more conveniently. We allow the second one because otherwise it'd be invalid syntax since symbols like `-` and others are usually reserved.
12567+
12568+## Type Declaration
12569+
12570+Although **optional**, you can still pre-declare a poly variant type:
12571+
12572+```res nocheck
12573+// Note the surrounding square brackets, and # for constructors
12574+type color = [#red | #green | #blue]
12575+```
12576+
12577+These types can also be inlined, unlike for regular variant:
12578+
12579+<CodeTab labels={["ReScript", "JS Output"]}>
12580+
12581+```res
12582+let render = (myColor: [#red | #green | #blue]) => {
12583+ switch myColor {
12584+ | #blue => Console.log("Hello blue!")
12585+ | #red
12586+ | #green => Console.log("Hello other colors")
12587+ }
12588+}
12589+```
12590+
12591+```js
12592+function render(myColor) {
12593+ if (myColor === "green" || myColor === "red") {
12594+ console.log("Hello other colors");
12595+ } else {
12596+ console.log("Hello blue!");
12597+ }
12598+}
12599+
12600+export { render };
12601+```
12602+
12603+</CodeTab>
12604+
12605+**Note**: because a poly variant value's type definition is **inferred** and not searched in the scope, the following snippet won't error:
12606+
12607+<CodeTab labels={["ReScript", "JS Output"]}>
12608+
12609+```res
12610+type color = [#red | #green | #blue]
12611+
12612+let render = myColor => {
12613+ switch myColor {
12614+ | #blue => Console.log("Hello blue!")
12615+ | #green => Console.log("Hello green!")
12616+ // works!
12617+ | #yellow => Console.log("Hello yellow!")
12618+ }
12619+}
12620+```
12621+
12622+```js
12623+function render(myColor) {
12624+ if (myColor === "yellow") {
12625+ console.log("Hello yellow!");
12626+ } else if (myColor === "green") {
12627+ console.log("Hello green!");
12628+ } else {
12629+ console.log("Hello blue!");
12630+ }
12631+}
12632+
12633+export { render };
12634+```
12635+
12636+</CodeTab>
12637+
12638+That `myColor` parameter's type is inferred to be `#red`, `#green` or `#yellow`, and is unrelated to the `color` type. If you intended `myColor` to be of type `color`, annotate it as `myColor: color` in any of the places.
12639+
12640+## Constructor Arguments
12641+
12642+This is similar to a regular variant's [constructor arguments](./variant.mdx#constructor-arguments):
12643+
12644+<CodeTab labels={["ReScript", "JS Output"]}>
12645+
12646+```res
12647+type account = [
12648+ | #Anonymous
12649+ | #Instagram(string)
12650+ | #Facebook(string, int)
12651+]
12652+
12653+let me: account = #Instagram("Jenny")
12654+let him: account = #Facebook("Josh", 26)
12655+```
12656+
12657+```js
12658+let me = {
12659+ NAME: "Instagram",
12660+ VAL: "Jenny",
12661+};
12662+
12663+let him = {
12664+ NAME: "Facebook",
12665+ VAL: ["Josh", 26],
12666+};
12667+
12668+export { me, him };
12669+```
12670+
12671+</CodeTab>
12672+
12673+### Combine Types and Pattern Match
12674+
12675+You can use poly variant types within other poly variant types to create a sum of all constructors:
12676+
12677+<CodeTab labels={["ReScript", "JS Output"]}>
12678+
12679+```res
12680+type red = [#Ruby | #Redwood | #Rust]
12681+type blue = [#Sapphire | #Neon | #Navy]
12682+
12683+// Contains all constructors of red and blue.
12684+// Also adds #Papayawhip
12685+type color = [red | blue | #Papayawhip]
12686+
12687+let myColor: color = #Ruby
12688+```
12689+
12690+```js
12691+let myColor = "Ruby";
12692+
12693+export { myColor };
12694+```
12695+
12696+</CodeTab>
12697+
12698+There's also some special [pattern matching](./pattern-matching-destructuring.mdx) syntax to match on constructors defined in a specific poly variant type:
12699+
12700+<CodeTab labels={["ReScript", "JS Output"]}>
12701+
12702+```res nocheck
12703+// Continuing the previous example above...
12704+
12705+switch myColor {
12706+| #...blue => Console.log("This blue-ish")
12707+| #...red => Console.log("This red-ish")
12708+| other => Console.log2("Other color than red and blue: ", other)
12709+}
12710+```
12711+
12712+```js
12713+var other = myColor;
12714+
12715+if (other === "Neon" || other === "Navy" || other === "Sapphire") {
12716+ console.log("This is blue-ish");
12717+} else if (other === "Rust" || other === "Ruby" || other === "Redwood") {
12718+ console.log("This is red-ish");
12719+} else {
12720+ console.log("Other color than red and blue: ", other);
12721+}
12722+```
12723+
12724+</CodeTab>
12725+
12726+This is a shorter version of:
12727+
12728+```res nocheck
12729+switch myColor {
12730+| #Sapphire | #Neon | #Navy => Console.log("This is blue-ish")
12731+| #Ruby | #Redwood | #Rust => Console.log("This is red-ish")
12732+| other => Console.log2("Other color than red and blue: ", other)
12733+}
12734+```
12735+
12736+## Structural Sharing
12737+
12738+Since poly variants value don't have a source of truth for their type, you can write such code:
12739+
12740+<CodeTab labels={["ReScript", "JS Output"]}>
12741+
12742+```res
12743+type preferredColors = [#white | #blue]
12744+
12745+let myColor: preferredColors = #blue
12746+
12747+let displayColor = v => {
12748+ switch v {
12749+ | #red => "Hello red"
12750+ | #green => "Hello green"
12751+ | #white => "Hey white!"
12752+ | #blue => "Hey blue!"
12753+ }
12754+}
12755+
12756+Console.log(displayColor(myColor))
12757+```
12758+
12759+```js
12760+function displayColor(v) {
12761+ if (v === "white") {
12762+ return "Hey white!";
12763+ } else if (v === "red") {
12764+ return "Hello red";
12765+ } else if (v === "green") {
12766+ return "Hello green";
12767+ } else {
12768+ return "Hey blue!";
12769+ }
12770+}
12771+
12772+console.log(displayColor("blue"));
12773+
12774+let myColor = "blue";
12775+
12776+export { myColor, displayColor };
12777+```
12778+
12779+</CodeTab>
12780+
12781+With a regular variant, the line `displayColor(myColor)` would fail, since it'd complain that the type of `myColor` doesn't match the type of `v`. No problem with poly variant.
12782+
12783+## JavaScript Output
12784+
12785+Poly variants are great for JavaScript interop! You can share their values to JS code, or model incoming JS values as poly variants.
12786+
12787+- `#red` and `#"I am red 😃"` compile to JavaScipt `"red"` and `"I am red 😃"`.
12788+- `#1` compiles to JavaScript `1`.
12789+- Poly variant constructor with 1 argument, like `Instagram("Jenny")` compile to a straightforward `{NAME: "Instagram", VAL: "Jenny"}`. 2 or more arguments like `#Facebook("Josh", 26)` compile to a similar object, but with `VAL` being an array of the arguments.
12790+
12791+### Bind to Functions
12792+
12793+For example, let's assume we want to bind to `Intl.NumberFormat` and want to make sure that our users only pass valid locales, we could define an external binding like this:
12794+
12795+<CodeTab labels={["ReScript", "JS Output"]}>
12796+
12797+```res
12798+type t
12799+
12800+@scope("Intl") @val
12801+external makeNumberFormat: ([#"de-DE" | #"en-GB" | #"en-US"]) => t = "NumberFormat"
12802+
12803+let intl = makeNumberFormat(#"de-DE")
12804+```
12805+
12806+```js
12807+let intl = Intl.NumberFormat("de-DE");
12808+
12809+export { intl };
12810+```
12811+
12812+</CodeTab>
12813+
12814+The JS output is identical to handwritten JS, but we also get to enjoy type errors if we accidentally write `makeNumberFormat(#"de-DR")`.
12815+
12816+More advanced usage examples for poly variant interop can be found in [Bind to JS Function](./bind-to-js-function.mdx#constrain-arguments-better).
12817+
12818+### Bind to String Enums
12819+
12820+Let's assume we have a TypeScript module that expresses following enum export:
12821+
12822+```js
12823+// direction.js
12824+enum Direction {
12825+ Up = "UP",
12826+ Down = "DOWN",
12827+ Left = "LEFT",
12828+ Right = "RIGHT",
12829+}
12830+
12831+export const myDirection = Direction.Up
12832+```
12833+
12834+For this particular example, we can also inline poly variant type definitions to design the type for the imported `myDirection` value:
12835+
12836+<CodeTab labels={["ReScript", "JS Output"]}>
12837+
12838+```res
12839+type direction = [ #UP | #DOWN | #LEFT | #RIGHT ]
12840+@module("./direction.js") external myDirection: direction = "myDirection"
12841+```
12842+
12843+```js
12844+import * as DirectionJs from "./direction.js";
12845+
12846+let myDirection = DirectionJs.myDirection;
12847+
12848+export { myDirection };
12849+```
12850+
12851+</CodeTab>
12852+
12853+Again: since we were using poly variants, the JS Output is practically zero-cost and doesn't add any extra code!
12854+
12855+## Extra Constraints on Types
12856+
12857+The previous poly variant type annotations we've looked at are the regular "closed" kind. However, there's a way to express "I want at least these constructors" (lower bound) and "I want at most these constructors" (upper bound):
12858+
12859+```res nocheck
12860+// Only #Red allowed. Closed.
12861+let basic: [#Red] = #Red
12862+
12863+// May contain #Red, or any other value. Open
12864+// here, foreground will actually be inferred as [> #Red | #Green]
12865+let foreground: [> #Red] = #Green
12866+
12867+// The value must be, at most, one of #Red or #Blue
12868+// Only #Red and #Blue are valid values
12869+let background: [< #Red | #Blue] = #Red
12870+```
12871+
12872+**Note:** We added this info for educational purposes. In most cases you will not want to use any of this stuff, since it makes your APIs pretty unreadable / hard to use.
12873+
12874+### Closed `[`
12875+
12876+This is the simplest poly variant definition, and also the most practical one. Like a common variant type, this one defines an exact set of constructors.
12877+
12878+```res nocheck
12879+type rgb = [ #Red | #Green | #Blue ]
12880+
12881+let color: rgb = #Green
12882+```
12883+
12884+In the example above, `color` will only allow one of the three constructors that are defined in the `rgb` type. This is usually the way how poly variants should be defined.
12885+
12886+In case you want to define a type that is extensible, you'll need to use the lower / upper bound syntax.
12887+
12888+### Lower Bound `[>`
12889+
12890+A lower bound defines the minimum set of constructors a poly variant type is aware of. It is also considered an "open poly variant type", because it doesn't restrict any additional values.
12891+
12892+Here is an example on how to make a minimum set of `basicBlueTones` extensible for a new `color` type:
12893+
12894+```res nocheck
12895+type basicBlueTone<'a> = [> #Blue | #DeepBlue | #LightBlue ] as 'a
12896+type color = basicBlueTone<[#Blue | #DeepBlue | #LightBlue | #Purple]>
12897+
12898+let color: color = #Purple
12899+
12900+// This will fail due to missing minimum constructors:
12901+type notWorking = basicBlueTone<[#Purple]>
12902+```
12903+
12904+Here, the compiler will enforce the user to define `#Blue | #DeepBlue | #LightBlue` as the minimum set of constructors when trying to extend `basicBlueTone<'a>`.
12905+
12906+**Note:** Since we want to define an extensible poly variant, we need to provide a type placeholder `<'a>`, and also add `as 'a` after the poly variant declaration, which essentially means: "Given type `'a` is constraint to the minimum set of constructors (`#Blue | #DeepBlue | #LightBlue`) defined in `basicBlueTone`".
12907+
12908+### Upper Bound `[<`
12909+
12910+The upper bound works in the opposite way than a lower bound: the extending type may only use constructors that are stated in the upper bound constraint.
12911+
12912+Here another example, but with red colors:
12913+
12914+```res nocheck
12915+type validRed<'a> = [< #Fire | #Crimson | #Ash] as 'a
12916+type myReds = validRed<[#Ash]>
12917+
12918+// This will fail due to unlisted constructor not defined by the lower bound
12919+type notWorking = validRed<[#Purple]>
12920+```
12921+
12922+## Coercion
12923+
12924+You can convert a poly variant to a `string` or `int` at no cost:
12925+
12926+<CodeTab labels={["ReScript", "JS Output"]}>
12927+
12928+```res
12929+type company = [#Apple | #Facebook]
12930+let theCompany: company = #Apple
12931+
12932+let message = "Hello " ++ (theCompany :> string)
12933+```
12934+
12935+```js
12936+let message = "Hello " + "Apple";
12937+
12938+let theCompany = "Apple";
12939+
12940+export { theCompany, message };
12941+```
12942+
12943+</CodeTab>
12944+
12945+**Note**: for the coercion to work, the poly variant type needs to be closed; you'd need to annotate it, since otherwise, `theCompany` would be inferred as `[> #Apple]`.
12946+
12947+## Tips & Tricks
12948+
12949+### Variant vs Polymorphic Variant
12950+
12951+One might think that polymorphic variants are superior to regular [variants](./variant.mdx). As always, there are trade-offs:
12952+
12953+- Due to their "structural" nature, poly variant's type errors might be more confusing. If you accidentally write `#blur` instead of `#blue`, ReScript will still error but can't indicate the correct source as easily. Regular variants' source of truth is the type definition, so the error can't go wrong.
12954+- It's also harder to refactor poly variants. Consider this:
12955+
12956+ ```res
12957+ let myFruit = #Apple
12958+ let mySecondFruit = #Apple
12959+ let myCompany = #Apple
12960+ ```
12961+
12962+ Refactoring the first one to `#Orange` doesn't mean we should refactor the third one. Therefore, the editor plugin can't touch the second one either. Regular variant doesn't have such problem, as these 2 values presumably come from different variant type definitions.
12963+
12964+- You might lose some nice pattern match checks from the compiler:
12965+
12966+ ```res
12967+ let myColor = #red
12968+
12969+ switch myColor {
12970+ | #red => Console.log("Hello red!")
12971+ | #blue => Console.log("Hello blue!")
12972+ }
12973+ ```
12974+
12975+ Because there's no poly variant definition, it's hard to know whether the `#blue` case can be safely removed.
12976+
12977+In most scenarios, we'd recommend to use regular variants over polymorphic variants, especially when you are writing plain ReScript code. In case you want to write zero-cost interop bindings or generate clean JS output, poly variants are oftentimes a better option.
12978+
12979+---
12980+title: "Primitive Types"
12981+description: "Primitive Data Types in ReScript"
12982+canonical: "/docs/manual/primitive-types"
12983+section: "Language Features"
12984+order: 4
12985+---
12986+
12987+# Primitive Types
12988+
12989+ReScript comes with the familiar primitive types like `string`, `int`, `float`, etc.
12990+
12991+{/* TODO: doc unit */}
12992+
12993+## String
12994+
12995+ReScript `string`s are delimited using **double** quotes (single quotes are reserved for the character type below).
12996+
12997+<CodeTab labels={["ReScript", "JS Output"]}>
12998+
12999+```res
13000+let greeting = "Hello world!"
13001+let multilineGreeting = "Hello
13002+ world!"
13003+```
13004+
13005+```js
13006+let greeting = "Hello world!";
13007+
13008+let multilineGreeting = "Hello\n world!";
13009+
13010+export { greeting, multilineGreeting };
13011+```
13012+
13013+</CodeTab>
13014+
13015+To concatenate strings, use `++`:
13016+
13017+<CodeTab labels={["ReScript", "JS Output"]}>
13018+
13019+```res
13020+let greetings = "Hello " ++ "world!"
13021+```
13022+
13023+```js
13024+let greetings = "Hello world!";
13025+
13026+export { greetings };
13027+```
13028+
13029+</CodeTab>
13030+
13031+Since both sides of the concatenation are known, the JS output becomes a single string literal.
13032+
13033+### String Interpolation
13034+
13035+There's a special syntax for string that allows
13036+
13037+- multiline string just like before
13038+- no special character escaping
13039+- Interpolation
13040+
13041+<CodeTab labels={["ReScript", "JS Output"]}>
13042+
13043+```res
13044+let name = "Joe"
13045+
13046+let greeting = `Hello
13047+World
13048+👋
13049+${name}
13050+`
13051+```
13052+
13053+```js
13054+let name = "Joe";
13055+
13056+let greeting =
13057+ `Hello
13058+World
13059+👋
13060+` +
13061+ name +
13062+ `
13063+`;
13064+
13065+export { name, greeting };
13066+```
13067+
13068+</CodeTab>
13069+
13070+This is just like JavaScript's backtick string interpolation, except without needing to escape special characters.
13071+
13072+### Usage
13073+
13074+See the familiar `String` API in the [API docs](/docs/manual/api/stdlib/string). Since a ReScript string maps to a JavaScript string, you can mix & match the string operations in all standard libraries.
13075+
13076+### Tips & Tricks
13077+
13078+**You have a good type system now!** In an untyped language, you'd often overload the meaning of string by using it as:
13079+
13080+- a unique id: `var BLUE_COLOR = "blue"`
13081+- an identifier into a data structure: `var BLUE = "blue" var RED = "red" var colors = [BLUE, RED]`
13082+- the name of an object field: `person["age"] = 24`
13083+- an enum: `if (audio.canPlayType() === 'probably') {...}` [(ಠ_ಠ)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType#Return_value)
13084+- other crazy patterns you'll soon find horrible, after getting used to ReScript's alternatives.
13085+
13086+The more you overload the poor string type, the less the type system (or a teammate) can help you! ReScript provides concise, fast and maintainable types & data structures alternatives to the use-cases above (e.g. [variants](./variant.mdx)).
13087+
13088+## Char
13089+
13090+ReScript has a type for a string with a single letter:
13091+
13092+<CodeTab labels={["ReScript", "JS Output"]}>
13093+
13094+```res
13095+let firstLetterOfAlphabet = 'a'
13096+```
13097+
13098+```js
13099+let firstLetterOfAlphabet = /* 'a' */ 97;
13100+
13101+export { firstLetterOfAlphabet };
13102+```
13103+
13104+</CodeTab>
13105+
13106+**Note**: Char doesn't support Unicode or UTF-8 and is therefore not recommended.
13107+
13108+To convert a String to a Char, use `String.get("a", 0)`. To convert a Char to a String, use `String.make(1, 'a')`.
13109+
13110+## Regular Expression
13111+
13112+ReScript regular expressions compile cleanly to their JavaScript counterpart:
13113+
13114+<CodeTab labels={["ReScript", "JS Output"]}>
13115+
13116+```res
13117+let r = /b/g
13118+```
13119+
13120+```js
13121+let r = /b/g;
13122+
13123+export { r };
13124+```
13125+
13126+</CodeTab>
13127+
13128+A regular expression like the above has the type `RegExp.t`. The [RegExp](/docs/manual/api/stdlib/regexp) module contains the regular expression helpers you have seen in JS.
13129+
13130+## Boolean
13131+
13132+A ReScript boolean has the type `bool` and can be either `true` or `false`. Common operations:
13133+
13134+- `&&`: logical and.
13135+- `||`: logical or.
13136+- `!`: logical not.
13137+- `<=`, `>=`, `<`, `>`
13138+- `==`: structural equal, compares data structures deeply. `(1, 2) == (1, 2)` is `true`. Convenient, but use with caution.
13139+- `===`: referential equal, compares shallowly. `(1, 2) === (1, 2)` is `false`. `let myTuple = (1, 2); myTuple === myTuple` is `true`.
13140+- `!=`: structural unequal.
13141+- `!==`: referential unequal.
13142+
13143+ReScript's `true/false` compiles into a JavaScript `true/false`.
13144+
13145+## Integers
13146+
13147+32-bits, truncated when necessary. We provide the usual operations on them: `+`, `-`, `*`, `/`, etc. See [Int](/docs/manual/api/stdlib/int) for helper functions.
13148+
13149+Integer operators include `+`, `-`, `*`, `/`, `**`, and `%`.
13150+
13151+`%` keeps the familiar `mod` naming, but its semantics are remainder (same behavior as JavaScript `%`).
13152+
13153+Bitwise operators for `int`: `~~~`, `&&&`, `|||`, `^^^`, `<<`, `>>`, `>>>`.
13154+
13155+**Be careful when you bind to JavaScript numbers!** Since ReScript integers have a much smaller range than JavaScript numbers, data might get lost when dealing with large numbers. In those cases it’s much safer to bind the numbers as **float**. Be extra mindful of this when binding to JavaScript Dates and their epoch time.
13156+
13157+To improve readability, you may place underscores in the middle of numeric literals such as `1_000_000`. Note that underscores can be placed anywhere within a number, not just every three digits.
13158+
13159+## Floats
13160+
13161+Arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`) work for both `int` and `float`. Like `0.5 + 0.6`. See [Float](/docs/manual/api/stdlib/float) for helper functions.
13162+
13163+As with integers, you may use underscores within literals to improve readability.
13164+
13165+### Int-to-Float Coercion
13166+
13167+`int` values can be coerced to `float` with the `:>` (type coercion) operator.
13168+
13169+<CodeTab labels={["ReScript", "JS Output"]}>
13170+
13171+```res
13172+let result = (1 :> float) + 2.
13173+```
13174+
13175+```js
13176+let result = 1 + 2;
13177+
13178+export { result };
13179+```
13180+
13181+</CodeTab>
13182+
13183+## Big Integers (experimental)
13184+
13185+**Since 11.1**
13186+
13187+For values which are too large to be represented by Int or Float, there is the `bigint` primitive type.
13188+We provide the usual operations on them: `+`, `-`, `*`, `/`, `**`, `%`, etc. See [BigInt](/docs/manual/api/stdlib/bigint) for helper functions.
13189+
13190+A `bigint` number is denoted by a trailing `n` like so: `42n`.
13191+
13192+As `bigint` is a different data type than `int`, it's necessary to open the corresponding module to overload the operators.
13193+
13194+<CodeTab labels={["ReScript", "JS Output"]}>
13195+
13196+```res
13197+open! BigInt
13198+
13199+let a = 9007199254740991n + 9007199254740991n
13200+let b = 2n ** 2n
13201+```
13202+
13203+```js
13204+let a = 9007199254740991n + 9007199254740991n;
13205+
13206+let b = 2n ** 2n;
13207+
13208+export { a, b };
13209+```
13210+
13211+</CodeTab>
13212+
13213+It also supports all the bitwise operations, except unsigned shift right (`>>>`), which is not supported by JS itself for `bigint`s.
13214+
13215+<CodeTab labels={["ReScript", "JS Output"]}>
13216+
13217+```res
13218+open! BigInt
13219+
13220+let a = 5n &&& 3n
13221+let b = 5n ||| 2n
13222+let c = 5n ^^^ 1n
13223+let d = ~~~5n
13224+let e = 5n << 1n
13225+let f = 5n >> 1n
13226+```
13227+
13228+```js
13229+let a = 5n & 3n;
13230+
13231+let b = 5n | 2n;
13232+
13233+let c = 5n ^ 1n;
13234+
13235+let d = ~5n;
13236+
13237+let e = 5n << 1n;
13238+
13239+let f = 5n >> 1n;
13240+
13241+export { a, b, c, d, e, f };
13242+```
13243+
13244+</CodeTab>
13245+
13246+It can also be pattern-matched.
13247+
13248+<CodeTab labels={["ReScript", "JS Output"]}>
13249+
13250+```res
13251+let bigintValue = 1n
13252+
13253+switch bigintValue {
13254+| 1n => Console.log("Small bigint")
13255+| 100n => Console.log("Larger bigint")
13256+| _ => Console.log("Other bigint")
13257+}
13258+```
13259+
13260+```js
13261+console.log("Small bigint");
13262+
13263+let bigintValue = 1n;
13264+
13265+export { bigintValue };
13266+```
13267+
13268+</CodeTab>
13269+
13270+## Unit
13271+
13272+The `unit` type indicates the absence of a specific value. It has only a single value, `()`, which acts as a placeholder when no other value exists or is needed. It compiles to JavaScript's `undefined` and resembles the `void` type in languages such as C++. What's the point of such a type?
13273+
13274+Consider the `Math.random` function. Its type signature is `unit => float`, which means it receives a `unit` as input and calculates a random `float` as output. You use the function like this - `let x = Math.random()`. Notice `()` as the first and only function argument.
13275+
13276+Imagine a simplified `Console.log` function that prints a message. Its type signature is `string => unit` and you'd use it like this `Console.log("Hello!")`. It takes a string as input, prints it, and then returns nothing useful. When `unit` is the output of a function it means the function performs some kind of side-effect.
13277+
13278+## Unknown
13279+
13280+The `unknown` type represents values with contents that are a mystery or are not 100% guaranteed to be what you think they are. It provides type-safety when interacting with data received from an untrusted source. For example, suppose an external function is supposed to return a `string`. It might. But if the documentation is not accurate or the code has bugs, the function could return `null`, an `array`, or something else you weren't expecting.
13281+
13282+The ReScript type system helps you avoid run-time crashes and unpredicatable behavior by preventing you from using `unknown` in places that expect a `string` or `int` or some other type. The ReScript core libraries also provide utility functions to help you inspect `unknown` values and access their contents. In some cases you may need a JSON parsing library to convert `unknown` values to types you can safely use.
13283+
13284+Consider using `unknown` when receiving data from [external JavaScript functions](./bind-to-js-function.mdx)
13285+
13286+---
13287+title: "Project Structure"
13288+description: "Notes on project structure and other rough ReScript guidelines"
13289+canonical: "/docs/manual/project-structure"
13290+section: "Guides"
13291+order: 3
13292+---
13293+
13294+# Project Structure
13295+
13296+These are the existing, non-codified community practices that are currently propagated through informal agreement. We might remove some of them at one point, and enforce some others. Right now, they're just recommendations for ease of newcomers.
13297+
13298+## File Casing
13299+
13300+Capitalized file names (aka first letter upper-cased).
13301+
13302+**Justification**: Module names can only be capitalized. Newcomers often ask how a file maps to a module, and why `draw.res` maps to the module `Draw`, and sometimes try to refer to a module through uncapitalized identifiers. Using `Draw.res` makes this mapping more straightforward. It also helps certain file names that'd be awkward in uncapitalized form: `uRI.res`.
13303+
13304+## Ignore `.merlin` File
13305+
13306+This is generated by the build system and you should not have to manually edit it. Don't check it into the repo.
13307+
13308+**Justification**: `.merlin` is for editor tooling. The file contains absolute paths, which are also not cross-platform (e.g. Windows paths are different).
13309+
13310+## Folders
13311+
13312+Try not to have too many nested folders. Keep your project flat, and have fewer files (reminder: you can use nested modules).
13313+
13314+**Justification**: The file system is a _tree_, but your code's dependencies are a _graph_. Because of that, any file & folder organization is usually imperfect. While it's still valuable to group related files together in a folder, the time wasted debating & getting decision paralysis over these far outweight their benefits. We'll always recommend you to Get Work Done instead of debating about these issues.
13315+
13316+## Third-party Dependencies
13317+
13318+Keep them to a minimum.
13319+
13320+**Justification**: A compiled, statically typed language cannot model its dependencies easily by muddling along like in a dynamic language, especially when we're still piggy-backing on NPM/Yarn (to reduce learning overhead in the medium-term). Keeping dependencies simple & lean helps reduce possibility of conflicts (e.g. two diamond dependencies, or clashing interfaces).
13321+
13322+## Documentation
13323+
13324+Have them. Spend more effort making them great (examples, pitfalls) and professional rather than _just_ fancy-looking. Do use examples, and avoid using names such as `foo` and `bar`. There's always more concrete names (it's an example, no need to be abstract/generalized just yet. The API docs will do this plentily). For blog posts, don't repeat the docs themselves, describe the _transition_ from old to new, and why (e.g. "it was a component, now it's a function, because ...").
13325+
13326+**Justification**: It's hard for newcomers to distinguish between a simple/decent library and one that's fancy-looking. For the sake of the community, don't try too hard to one-up each other's libraries. Do spread the words, but use your judgement too.
13327+
13328+## PPX & Other Meta-tools
13329+
13330+Keep them to a minimum. PPX, unless used in renown cases (printer, accessors and serializer/deserializer generation), can cause big learning churn for newcomers; on top of the syntax, semantics, types, build tool & FFI that they already have to learn, learning per-library custom transformations of the code is an extra step. More invasive macros makes the code itself less semantically meaningful too, since the essence would be hiding somewhere else.
13331+
13332+## Paradigm
13333+
13334+Don't abuse overly fancy features. Do leave some breathing room for future APIs but don't over-architect things.
13335+
13336+**Justification**: Simple code helps newcomers understand and potentially contribute to your code. Contributing is the best way for them to learn. The extra help you receive might also surpass the gain of using a slightly more clever language trick. But do try new language tricks in some of more casual projects! You might discover new ways of architecting code.
13337+
13338+## Publishing
13339+
13340+If it's a wrapper for a JS library, don't publish the JS artifacts. If it's a legit library, publish the artifacts in lib/js if you think JS consumers might use it. This is especially the case when you gradually convert a JS lib to ReScript while not breaking existing JS consumers.
13341+
13342+Do put the keywords `"rescript"` in your package.json `keywords` field. This allows us to find the library much more easily for future purposes.
13343+
13344+**Justification**: Be nice to JS consumers of your library. They're your future ReScripters.
13345+
13346+---
13347+title: "Promises"
13348+description: "JS Promise handling in ReScript"
13349+canonical: "/docs/manual/promise"
13350+section: "Language Features"
13351+order: 21
13352+---
13353+
13354+# Promise
13355+
13356+> **Note:** Starting from ReScript 10.1 and above, we recommend using [async / await](./async-await.mdx) when interacting with Promises.
13357+
13358+## `promise` type
13359+
13360+**Since 10.1**
13361+
13362+In ReScript, every JS promise is represented with the globally available `promise<'a>` type.
13363+
13364+Here's a usage example in a function signature:
13365+
13366+```resi
13367+// User.resi file
13368+
13369+type user = {name: string}
13370+
13371+let fetchUser: string => promise<user>
13372+```
13373+
13374+To work with promise values (instead of using `async` / `await`) you may want to use the built-in `Promise` module.
13375+
13376+## Promise
13377+
13378+A builtin module to create, chain and manipulate promises.
13379+
13380+### Creating a promise
13381+
13382+```res
13383+let p1 = Promise.make((resolve, reject) => {
13384+ resolve("hello world")
13385+})
13386+
13387+let p2 = Promise.resolve("some value")
13388+
13389+// You can only reject `exn` values for streamlined catch handling
13390+exception MyOwnError(string)
13391+let p3 = Promise.reject(MyOwnError("some rejection"))
13392+```
13393+
13394+### Access the contents and transform a promise
13395+
13396+```res
13397+let logAsyncMessage = () => {
13398+ open Promise
13399+ Promise.resolve("hello world")
13400+ ->then(msg => {
13401+ // then callbacks require the result to be resolved explicitly
13402+ resolve("Message: " ++ msg)
13403+ })
13404+ ->then(msg => {
13405+ Console.log(msg)
13406+
13407+ // Even if there is no result, we need to use resolve() to return a promise
13408+ resolve()
13409+ })
13410+ ->ignore // Requires ignoring due to unhandled return value
13411+}
13412+```
13413+
13414+For comparison, the `async` / `await` version of the same code would look like this:
13415+
13416+```res
13417+let logAsyncMessage = async () => {
13418+ let msg = await Promise.resolve("hello world")
13419+ Console.log(`Message: ${msg}`)
13420+}
13421+```
13422+
13423+Needless to say, the async / await version offers better ergonomics and less opportunities to run into type issues.
13424+
13425+### Handling Rejected Promises
13426+
13427+You can handle a rejected promise using the [`Promise.catch()`](/docs/manual/api/stdlib/promise#value-catch) method, which allows you to catch and manage errors effectively.
13428+
13429+### Run multiple promises in parallel
13430+
13431+In case you want to launch multiple promises in parallel, use `Promise.all`:
13432+
13433+<CodeTab labels={["ReScript", "JS Output"]}>
13434+
13435+```res
13436+@val
13437+external fetchMessage: string => promise<string> = "global.fetchMessage"
13438+
13439+let logAsyncMessage = async () => {
13440+ let messages = await Promise.all([fetchMessage("message1"), fetchMessage("message2")])
13441+
13442+ Console.log(messages->Array.joinWith(", "))
13443+}
13444+```
13445+
13446+```js
13447+async function logAsyncMessage() {
13448+ let messages = await Promise.all([
13449+ global.fetchMessage("message1"),
13450+ global.fetchMessage("message2"),
13451+ ]);
13452+ console.log(messages.join(", "));
13453+}
13454+
13455+export { logAsyncMessage };
13456+```
13457+
13458+</CodeTab>
13459+
13460+---
13461+title: "Record"
13462+description: "Record types in ReScript"
13463+canonical: "/docs/manual/record"
13464+section: "Language Features"
13465+order: 6
13466+---
13467+
13468+# Record
13469+
13470+Records are like JavaScript objects but:
13471+
13472+- are immutable by default
13473+- have fixed fields (not extensible)
13474+
13475+## Type Declaration
13476+
13477+A record needs a mandatory type declaration:
13478+
13479+<CodeTab labels={["ReScript", "JS Output"]}>
13480+
13481+```res prelude
13482+type person = {
13483+ age: int,
13484+ name: string,
13485+}
13486+```
13487+
13488+```js
13489+// Empty output
13490+```
13491+
13492+</CodeTab>
13493+
13494+You can also nest definitions of records.
13495+
13496+<CodeTab labels={["ReScript", "JS Output"]}>
13497+
13498+```res
13499+type nestedPerson = {
13500+ age: int,
13501+ name: string,
13502+ notificationSettings: {
13503+ sendEmails: bool,
13504+ allowPasswordLogin: bool,
13505+ },
13506+}
13507+
13508+let person = {
13509+ age: 90,
13510+ name: "Test Person",
13511+ notificationSettings: {
13512+ sendEmails: true,
13513+ allowPasswordLogin: false,
13514+ },
13515+}
13516+
13517+```
13518+
13519+```js
13520+let person = {
13521+ age: 90,
13522+ name: "Test Person",
13523+ notificationSettings: {
13524+ sendEmails: true,
13525+ allowPasswordLogin: false,
13526+ },
13527+};
13528+
13529+export { person };
13530+```
13531+
13532+</CodeTab>
13533+
13534+Nesting record definitions is a nice way to group records that are part of the same structure, and won't be referenced from the outside.
13535+
13536+If you end up needing to refer to a nested record type explicitly, you should make it an explicit definition instead of a nested one. This is mainly for 2 reasons:
13537+
13538+- The records that are automatically generated for the nested record definitions are named in a way that would require you to use escaped identifiers to reference them. The nested record at `notificationSettings` above would be named `\"person.notificationSettings"` for instance
13539+- For the sake of clarity (and caring about your co-workers), having an explicit and named definition to look at and refer to is much easier than scanning a potentially large record definition for the nested record you're looking for
13540+
13541+So if we in the example above ended up needing to refer to `person.notificationSettings` nested record from the outside, we should instead make it explicit, just like how we normally define records:
13542+
13543+<CodeTab labels={["ReScript", "JS Output"]}>
13544+
13545+```res
13546+type personNotificationSettings = {
13547+ sendEmails: bool,
13548+ allowPasswordLogin: bool,
13549+}
13550+
13551+type explicitPerson = {
13552+ age: int,
13553+ name: string,
13554+ notificationSettings: personNotificationSettings
13555+}
13556+
13557+let person = {
13558+ age: 90,
13559+ name: "Test Person",
13560+ notificationSettings: {
13561+ sendEmails: true,
13562+ allowPasswordLogin: false,
13563+ },
13564+}
13565+
13566+```
13567+
13568+```js
13569+let person = {
13570+ age: 90,
13571+ name: "Test Person",
13572+ notificationSettings: {
13573+ sendEmails: true,
13574+ allowPasswordLogin: false,
13575+ },
13576+};
13577+
13578+export { person };
13579+```
13580+
13581+</CodeTab>
13582+
13583+## Creation
13584+
13585+To create a `person` record (declared above):
13586+
13587+<CodeTab labels={["ReScript", "JS Output"]}>
13588+
13589+```res prelude
13590+let me = {
13591+ age: 5,
13592+ name: "Big ReScript"
13593+}
13594+```
13595+
13596+```js
13597+var me = {
13598+ age: 5,
13599+ name: "Big ReScript",
13600+};
13601+```
13602+
13603+</CodeTab>
13604+
13605+When you create a new record value, ReScript tries to find a record type declaration that conforms to the shape of the value. So the `me` value here is inferred as of type `person`.
13606+
13607+The type is found by looking above the `me` value. **Note**: if the type instead resides in another file or module, you need to explicitly indicate which file or module it is:
13608+
13609+<CodeTab labels={["ReScript", "JS Output"]}>
13610+
13611+```res
13612+// School.res
13613+type schoolPerson = {age: int, name: string}
13614+```
13615+
13616+```js
13617+let me = {
13618+ age: 5,
13619+ name: "Big ReScript",
13620+};
13621+
13622+export { me };
13623+```
13624+
13625+</CodeTab>
13626+
13627+<CodeTab labels={["ReScript", "JS Output"]}>
13628+
13629+```res nocheck
13630+// Example.res
13631+
13632+let me: School.schoolPerson = {age: 20, name: "Big ReScript"}
13633+/* or */
13634+let me2 = {School.age: 20, name: "Big ReScript"}
13635+```
13636+
13637+```js
13638+var me = {
13639+ age: 20,
13640+ name: "Big ReScript",
13641+};
13642+var me2 = {
13643+ age: 20,
13644+ name: "Big ReScript",
13645+};
13646+```
13647+
13648+</CodeTab>
13649+
13650+In both `me` and `me2` the record definition from `School` is found. The first one, `me` with the regular type annotation, is preferred.
13651+
13652+## Access
13653+
13654+Use the familiar dot notation:
13655+
13656+<CodeTab labels={["ReScript", "JS Output"]}>
13657+
13658+```res
13659+let name = me.name
13660+```
13661+
13662+```js
13663+let me = {
13664+ age: 5,
13665+ name: "Big ReScript",
13666+};
13667+
13668+let name = "Big ReScript";
13669+
13670+export { me, name };
13671+```
13672+
13673+</CodeTab>
13674+
13675+## Immutable Update
13676+
13677+New records can be created from old records with the `...` spread operator. The original record isn't mutated.
13678+
13679+<CodeTab labels={["ReScript", "JS Output"]}>
13680+
13681+```res
13682+let meNextYear = {...me, age: me.age + 1}
13683+```
13684+
13685+```js
13686+let meNextYear = {
13687+ age: 6,
13688+ name: "Big ReScript",
13689+};
13690+
13691+let me = {
13692+ age: 5,
13693+ name: "Big ReScript",
13694+};
13695+
13696+export { me, meNextYear };
13697+```
13698+
13699+</CodeTab>
13700+
13701+**Note**: spread cannot add new fields to the record value, as a record's shape is fixed by its type.
13702+
13703+## Mutable Update
13704+
13705+Record fields can optionally be mutable. This allows you to efficiently update those fields in-place with the `=` operator.
13706+
13707+<CodeTab labels={["ReScript", "JS Output"]}>
13708+
13709+```res
13710+type mutablePerson = {
13711+ name: string,
13712+ mutable age: int
13713+}
13714+
13715+let baby: mutablePerson = {name: "Baby ReScript", age: 5}
13716+baby.age = baby.age + 1 // `baby.age` is now 6. Happy birthday!
13717+```
13718+
13719+```js
13720+let baby = {
13721+ name: "Baby ReScript",
13722+ age: 5,
13723+};
13724+
13725+baby.age = (baby.age + 1) | 0;
13726+
13727+let me = {
13728+ age: 5,
13729+ name: "Big ReScript",
13730+};
13731+
13732+export { me, baby };
13733+```
13734+
13735+</CodeTab>
13736+
13737+Fields not marked with `mutable` in the type declaration cannot be mutated.
13738+
13739+## JavaScript Output
13740+
13741+ReScript records compile to straightforward JavaScript objects; see the various JS output tabs above.
13742+
13743+## Optional Record Fields
13744+
13745+ReScript [`v10`](../../blog/release-10-0-0.mdx#experimental-optional-record-fields) introduced optional record fields. This means that you can define fields that can be omitted when creating the record. It looks like this:
13746+
13747+<CodeTab labels={["ReScript", "JS Output"]}>
13748+
13749+```res
13750+type optionalPerson = {
13751+ age: int,
13752+ name?: string
13753+}
13754+```
13755+
13756+```js
13757+let me = {
13758+ age: 5,
13759+ name: "Big ReScript",
13760+};
13761+
13762+export { me };
13763+```
13764+
13765+</CodeTab>
13766+
13767+Notice how `name` has a suffixed `?`. That means that the field itself is _optional_.
13768+
13769+### Creation
13770+
13771+You can omit any optional fields when creating a record. Not setting an optional field will default the field's value to `None`:
13772+
13773+<CodeTab labels={["ReScript", "JS Output"]}>
13774+
13775+```res
13776+type optionalPerson = {
13777+ age: int,
13778+ name?: string
13779+}
13780+
13781+let me: optionalPerson = {
13782+ age: 5,
13783+ name: "Big ReScript"
13784+}
13785+
13786+let friend: optionalPerson = {
13787+ age: 7
13788+}
13789+```
13790+
13791+```js
13792+let me = {
13793+ age: 5,
13794+ name: "Big ReScript",
13795+};
13796+
13797+let friend = {
13798+ age: 7,
13799+};
13800+
13801+export { me, friend };
13802+```
13803+
13804+</CodeTab>
13805+
13806+This has consequences for pattern matching, which we'll expand a bit on soon.
13807+
13808+## Immutable Update
13809+
13810+Updating an optional field via an immutable update above lets you set that field value without needing to care whether it's optional or not.
13811+
13812+<CodeTab labels={["ReScript", "JS Output"]}>
13813+
13814+```res
13815+type personWithOptionalName = {
13816+ age: int,
13817+ name?: string
13818+}
13819+
13820+let me: personWithOptionalName = {
13821+ age: 123,
13822+ name: "Hello"
13823+}
13824+
13825+let withoutName = {
13826+ ...me,
13827+ name: "New Name"
13828+}
13829+```
13830+
13831+```js
13832+let me = {
13833+ age: 123,
13834+ name: "Hello",
13835+};
13836+
13837+let newrecord = { ...me };
13838+
13839+newrecord.name = "New Name";
13840+
13841+let withoutName = newrecord;
13842+
13843+export { me, withoutName };
13844+```
13845+
13846+</CodeTab>
13847+
13848+However, if you want to set the field to an optional value, you prefix that value with `?`:
13849+
13850+<CodeTab labels={["ReScript", "JS Output"]}>
13851+
13852+```res
13853+type personWithOptionalName = {
13854+ age: int,
13855+ name?: string
13856+}
13857+
13858+let me: personWithOptionalName = {
13859+ age: 123,
13860+ name: "Hello"
13861+}
13862+
13863+let maybeName = Some("My Name")
13864+
13865+let withoutName = {
13866+ ...me,
13867+ name: ?maybeName
13868+}
13869+```
13870+
13871+```js
13872+let me = {
13873+ age: 123,
13874+ name: "Hello",
13875+};
13876+
13877+let maybeName = "My Name";
13878+
13879+let newrecord = { ...me };
13880+
13881+newrecord.name = maybeName;
13882+
13883+let withoutName = newrecord;
13884+
13885+export { me, maybeName, withoutName };
13886+```
13887+
13888+</CodeTab>
13889+
13890+You can unset an optional field's value via that same mechanism by setting it to `?None`.
13891+
13892+### Pattern Matching on Optional Fields
13893+
13894+[Pattern matching](./pattern-matching-destructuring.mdx), one of ReScript's most important features, has two caveats when you deal with optional fields.
13895+
13896+When matching on the value directly, it's an `option`. Example:
13897+
13898+<CodeTab labels={["ReScript", "JS Output"]}>
13899+
13900+```res
13901+type matchedOptionalPerson = {
13902+ age: int,
13903+ name?: string,
13904+}
13905+
13906+let me: matchedOptionalPerson = {
13907+ age: 123,
13908+ name: "Hello",
13909+}
13910+
13911+let isRescript = switch me.name {
13912+| Some("ReScript") => true
13913+| Some(_) | None => false
13914+}
13915+```
13916+
13917+```js
13918+let isRescript = "Hello" === "ReScript";
13919+
13920+let me = {
13921+ age: 123,
13922+ name: "Hello",
13923+};
13924+
13925+export { me, isRescript };
13926+```
13927+
13928+</CodeTab>
13929+
13930+But, when matching on the field as part of the general record structure, it's treated as the underlying, non-optional value:
13931+
13932+<CodeTab labels={["ReScript", "JS Output"]}>
13933+
13934+```res
13935+type matchedOptionalRecord = {
13936+ age: int,
13937+ name?: string,
13938+}
13939+
13940+let me: matchedOptionalRecord = {
13941+ age: 123,
13942+ name: "Hello",
13943+}
13944+
13945+let isRescript = switch me {
13946+| {name: "ReScript"} => true
13947+| _ => false
13948+}
13949+
13950+```
13951+
13952+```js
13953+let isRescript = "Hello" === "ReScript";
13954+
13955+let me = {
13956+ age: 123,
13957+ name: "Hello",
13958+};
13959+
13960+export { me, isRescript };
13961+```
13962+
13963+</CodeTab>
13964+
13965+Sometimes you _do_ want to know whether the field was set or not. You can tell the pattern matching engine about that by prefixing your option match with `?`, like this:
13966+
13967+<CodeTab labels={["ReScript", "JS Output"]}>
13968+
13969+```res
13970+type matchedOptionalPerson = {
13971+ age: int,
13972+ name?: string,
13973+}
13974+
13975+let me: matchedOptionalPerson = {
13976+ age: 123,
13977+ name: "Hello",
13978+}
13979+
13980+let nameWasSet = switch me {
13981+| {name: ?None} => false
13982+| {name: ?Some(_)} => true
13983+}
13984+```
13985+
13986+```js
13987+let me = {
13988+ age: 123,
13989+ name: "Hello",
13990+};
13991+
13992+let nameWasSet = true;
13993+
13994+export { me, nameWasSet };
13995+```
13996+
13997+</CodeTab>
13998+
13999+## Record Type Spread
14000+
14001+In ReScript v11, you can now spread one or more record types into a new record type. It looks like this:
14002+
14003+```rescript
14004+type a = {
14005+ id: string,
14006+ name: string,
14007+}
14008+
14009+type b = {
14010+ age: int
14011+}
14012+
14013+type c = {
14014+ ...a,
14015+ ...b,
14016+ active: bool
14017+}
14018+```
14019+
14020+`type c` will now be:
14021+
14022+```rescript
14023+type c = {
14024+ id: string,
14025+ name: string,
14026+ age: int,
14027+ active: bool,
14028+}
14029+```
14030+
14031+Record type spreads act as a 'copy-paste' mechanism for fields from one or more records into a new record. This operation inlines the fields from the spread records directly into the new record definition, while preserving their original properties, such as whether they are optional or mandatory. It's important to note that duplicate field names are not allowed across the records being spread, even if the fields have the same type.
14032+
14033+## Record Type Coercion
14034+
14035+Record type coercion gives us more flexibility when passing around records in our application code. In other words, we can now coerce a record `a` to be treated as a record `b` at the type level, as long as the original record `a` contains the same set of fields in `b`. Here's an example:
14036+
14037+```rescript
14038+type a = {
14039+ name: string,
14040+ age: int,
14041+}
14042+
14043+type b = {
14044+ name: string,
14045+ age: int,
14046+}
14047+
14048+let nameFromB = (b: b) => b.name
14049+
14050+let a: a = {
14051+ name: "Name",
14052+ age: 35,
14053+}
14054+
14055+let name = nameFromB(a :> b)
14056+```
14057+
14058+Notice how we _coerced_ the value `a` to type `b` using the coercion operator `:>`. This works because they have the same record fields. This is purely at the type level, and does not involve any runtime operations.
14059+
14060+Additionally, we can also coerce records from `a` to `b` whenever `a` is a super-set of `b` (i.e. `a` containing all the fields of `b`, and more). The same example as above, slightly altered:
14061+
14062+```rescript
14063+type a = {
14064+ id: string,
14065+ name: string,
14066+ age: int,
14067+ active: bool,
14068+}
14069+
14070+type b = {
14071+ name: string,
14072+ age: int,
14073+}
14074+
14075+let nameFromB = (b: b) => b.name
14076+
14077+let a: a = {
14078+ id: "1",
14079+ name: "Name",
14080+ age: 35,
14081+ active: true,
14082+}
14083+
14084+let name = nameFromB(a :> b)
14085+```
14086+
14087+Notice how `a` now has more fields than `b`, but we can still coerce `a` to `b` because `b` has a subset of the fields of `a`.
14088+
14089+In combination with [optional record fields](./record.mdx#optional-record-fields), one may coerce a mandatory field of an `option` type to an optional field:
14090+
14091+```rescript
14092+type a = {
14093+ name: string,
14094+
14095+ // mandatory, but explicitly typed as option<int>
14096+ age: option<int>,
14097+}
14098+
14099+type b = {
14100+ name: string,
14101+ // optional field
14102+ age?: int,
14103+}
14104+
14105+let nameFromB = (b: b) => b.name
14106+
14107+let a: a = {
14108+ name: "Name",
14109+ age: Some(35),
14110+}
14111+
14112+let name = nameFromB(a :> b)
14113+```
14114+
14115+## Tips & Tricks
14116+
14117+### Record Types Are Found By Field Name
14118+
14119+With records, you **cannot** say "I'd like this function to take any record type, as long as they have the field `age`". The following **won't work as intended**:
14120+
14121+<CodeTab labels={["ReScript", "JS Output"]}>
14122+
14123+```res nocheck
14124+type person = {age: int, name: string}
14125+type monster = {age: int, hasTentacles: bool}
14126+
14127+let getAge = (entity) => entity.age
14128+```
14129+
14130+```js
14131+function getAge(entity) {
14132+ return entity.age;
14133+}
14134+```
14135+
14136+</CodeTab>
14137+
14138+Instead, `getAge` will infer that the parameter `entity` must be of type `monster`, the closest record type with the field `age`. The following code's last line fails:
14139+
14140+```res nocheck
14141+let kraken = {age: 9999, hasTentacles: true}
14142+let me = {age: 5, name: "Baby ReScript"}
14143+
14144+getAge(kraken)
14145+getAge(me) // type error!
14146+```
14147+
14148+The type system will complain that `me` is a `person`, and that `getAge` only works on `monster`. If you need such capability, use ReScript objects, described [here](./object.mdx).
14149+
14150+### Optional Fields in Records Can Be Useful for Bindings
14151+
14152+Many JavaScript APIs tend to have large configuration objects that can be a bit annoying to model as records, since you previously always needed to specify all record fields when creating a record.
14153+
14154+Optional record fields, introduced in [`v10`](../../blog/release-10-0-0.mdx#experimental-optional-record-fields), is intended to help with this. Optional fields will let you avoid having to specify all fields, and let you just specify the one's you care about. A significant improvement in ergonomics for bindings and other APIs with for example large configuration objects.
14155+
14156+## Design Decisions
14157+
14158+Why use records instead of objects?
14159+
14160+1. The truth is that most of the times in your app, your data's shape is actually fixed, and if it's not, it can potentially be better represented as a combination of variant (introduced next) + record instead.
14161+
14162+2. Since a record type is resolved through finding that single explicit type declaration (we call this "nominal typing"), the type error messages end up better than the counterpart ("structural typing", like for tuples). This makes refactoring easier; changing a record type's fields naturally allows the compiler to know that it's still the same record, just misused in some places. Otherwise, under structural typing, it might get hard to tell whether the definition site or the usage site is wrong.
14163+
14164+---
14165+title: "ReScript for JavaScript Developers"
14166+description: "A quick ReScript syntax guide for JavaScript developers"
14167+canonical: "/docs/manual/rescript-for-javascript-developers"
14168+section: "Overview"
14169+order: 3
14170+---
14171+
14172+# ReScript for JavaScript Developers
14173+
14174+If you already write JavaScript, ReScript should feel familiar quickly. This page is a compact syntax guide for the main differences you should be aware of.
14175+
14176+For a guided migration workflow, see [Converting from JS](./converting-from-js.mdx).
14177+
14178+## What to know first
14179+
14180+- `let` bindings are immutable by default. See [Let Binding](./let-binding.mdx) and [Mutation](./mutation.mdx).
14181+- ReScript does not use `null` and `undefined` as normal control flow. Reach for `option` instead. See [Null, Undefined and Option](./null-undefined-option.mdx).
14182+- Arrays must contain values of the same type. See [Array and List](./array-and-list.mdx) and [Tuple](./tuple.mdx).
14183+- Records are not ad-hoc JS objects; they have known field names and types. See [Record](./record.mdx) and [Object](./object.mdx).
14184+- Conditionals and blocks return values, so expression-oriented code is common. See [If-Else & Loops](./control-flow.mdx).
14185+- Pattern matching replaces many ad-hoc `if` or property-check branches. See [Pattern Matching / Destructuring](./pattern-matching-destructuring.mdx).
14186+
14187+## Quick reference
14188+
14189+| Topic | ReScript | Notes for JavaScript developers |
14190+| --------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
14191+| Semicolons | `let x = 1` | Semicolons are not required. See [Overview](./overview.mdx#semicolons). |
14192+| Comments | `//`, `/* */`, `/** */` | Familiar syntax, including doc comments. See [Overview](./overview.mdx#comments). |
14193+| Variables | `let x = 5` | `let` creates an immutable binding. See [Let Binding](./let-binding.mdx). |
14194+| Mutation | `let x = ref(5)` | Mutable state is explicit through `ref` or mutable fields. See [Mutation](./mutation.mdx). |
14195+| Strings | `"hello"` | Strings use double quotes. See [Primitive Types](./primitive-types.mdx). |
14196+| String concatenation | `"hello " ++ name` | ReScript uses `++` for strings. See [Primitive Types](./primitive-types.mdx). |
14197+| Interpolation | `` `hello ${name}` `` | Template strings work similarly. See [Primitive Types](./primitive-types.mdx). |
14198+| Equality | `===`, `!==`, `==`, `!=` | No coercive equality. `==` and `!=` are structural. See [Equality and Comparison](./equality-comparison.mdx). |
14199+| Numbers | `3`, `3.14`, `2.0 * 3.0` | Arithmetic operators work for both `int` and `float`. See [Primitive Types](./primitive-types.mdx). |
14200+| Records | `{x: 30, y: 20}` | Similar object syntax, but records are typed. See [Record](./record.mdx). |
14201+| Arrays | `[1, 2, 3]` | Arrays are homogeneous. See [Array and List](./array-and-list.mdx). |
14202+| Mixed fixed-size data | `(1, "Bob", true)` | Use tuples instead of heterogeneous arrays. See [Tuple](./tuple.mdx). |
14203+| Missing values | `option<'a>` | Use `Some(value)` and `None` instead of `null` and `undefined`. See [Null, Undefined and Option](./null-undefined-option.mdx). |
14204+| Functions | `let add = (a, b) => a + b` | Familiar arrow-style syntax. See [Function](./function.mdx). |
14205+| Blocks | `{ let x = 1; x + 1 }` | The last expression is returned implicitly. See [Overview](./overview.mdx#blocks). |
14206+| Conditionals | `if cond {a} else {b}` | `if` is an expression. See [If-Else & Loops](./control-flow.mdx). |
14207+| Pattern matching | `switch value { ... }` | Use `switch` for destructuring and exhaustive branching. See [Pattern Matching / Destructuring](./pattern-matching-destructuring.mdx). |
14208+| Destructuring | `let {a, b} = data` | Works for records, arrays, tuples, and more. See [Pattern Matching / Destructuring](./pattern-matching-destructuring.mdx). |
14209+| Loops | `for i in 0 to 10 {}` | `for` and `while` exist, but collection transforms are also common. See [If-Else & Loops](./control-flow.mdx). |
14210+| Exceptions | `throw(MyException(...))` | `throw` and `try` exist, but typed data flow is preferred where possible. See [Exception](./exception.mdx). |
14211+| JSX | `<Comp message />` | JSX is supported directly, with a few ReScript conventions. See [JSX](./jsx.mdx). |
14212+
14213+## Where to Go Next
14214+
14215+- For a broader syntax reference, see [Overview](./overview.mdx).
14216+- For a migration workflow inside an existing codebase, see [Converting from JS](./converting-from-js.mdx).
14217+- For JavaScript interop, see [Interop Cheatsheet](./interop-cheatsheet.mdx).
14218+- For importing and exporting JS modules, see [Import from Export to JS](./import-from-export-to-js.mdx).
14219+- For binding to JS objects and functions, see [Bind to JS Object](./bind-to-js-object.mdx) and [Bind to JS Function](./bind-to-js-function.mdx).
14220+
14221+---
14222+title: "Reserved Keywords"
14223+description: "All reserved keywords in ReScript"
14224+canonical: "/docs/manual/reserved-keywords"
14225+section: "Language Features"
14226+order: 27
14227+---
14228+
14229+# Reserved Keywords
14230+
14231+> **Note**: Some of these words are reserved purely for backward compatibility.
14232+>
14233+> If you _need_ to use one of these names as binding and/or field name, see [Use Illegal Identifier Names](./use-illegal-identifier-names.mdx).
14234+
14235+- `and`
14236+- `as`
14237+- `assert`
14238+
14239+{/* - `begin` */}
14240+
14241+{/* - `class` */}
14242+
14243+- `constraint`
14244+
14245+{/* - `do` */}
14246+{/* - `done` */}
14247+
14248+- `else`
14249+ {/* - `end` */}
14250+ {/* - `esfun` */}
14251+- `exception`
14252+- `external`
14253+
14254+* `false`
14255+* `for`
14256+ {/* - `fun` */}
14257+ {/* - `function` */}
14258+ {/* - `functor` */}
14259+
14260+- `if`
14261+- `in`
14262+- `include`
14263+ {/* - `inherit` */}
14264+ {/* - `initializer` */}
14265+
14266+* `lazy`
14267+* `let`
14268+
14269+- `module`
14270+- `mutable`
14271+
14272+{/* - `new` */}
14273+{/* - `nonrec` */}
14274+
14275+{/* - `object` */}
14276+
14277+- `of`
14278+- `open`
14279+ {/* - `or` */}
14280+
14281+{/* - `pri` */}
14282+{/* - `pub` */}
14283+
14284+- `rec`
14285+
14286+{/* - `sig` */}
14287+{/* - `struct` */}
14288+
14289+- `switch`
14290+
14291+{/* - `then` */}
14292+
14293+- `true`
14294+- `try`
14295+- `type`
14296+
14297+{/* - `val` */}
14298+{/* - `virtual` */}
14299+
14300+- `when`
14301+- `while`
14302+- `with`
14303+
14304+---
14305+title: "Scoped Polymorphic Types"
14306+description: "Scoped Polymorphic Types in ReScript"
14307+canonical: "/docs/manual/scoped-polymorphic-types"
14308+section: "Advanced Features"
14309+order: 2
14310+---
14311+
14312+# Scoped Polymorphic Types
14313+
14314+Scoped Polymorphic Types in ReScript are functions with the capability to handle arguments of any type within a specific scope. This feature is particularly valuable when working with JavaScript APIs, as it allows your functions to accommodate diverse data types while preserving ReScript's strong type checking.
14315+
14316+## Definition and Usage
14317+
14318+Scoped polymorphic types in ReScript offer a flexible and type-safe way to handle diverse data types within specific scopes. This documentation provides an example to illustrate their usage in a JavaScript context.
14319+
14320+### Example: Logging API
14321+
14322+Consider a logging example within a JavaScript context that processes various data types:
14323+
14324+```js
14325+const logger = {
14326+ log: (data) => {
14327+ if (typeof data === "string") {
14328+ /* handle string */
14329+ } else if (typeof data === "number") {
14330+ /* handle number */
14331+ } else {
14332+ /* handle other types */
14333+ }
14334+ },
14335+};
14336+```
14337+
14338+In ReScript, we can bind to this function as a record with a scoped polymorphic function type:
14339+
14340+```res prelude
14341+type logger = { log: 'a. 'a => unit }
14342+
14343+@module("jsAPI") external getLogger: unit => logger = "getLogger"
14344+```
14345+
14346+The `logger` type represents a record with a single field `log`, which is a scoped polymorphic function type `'a. 'a => unit`. The `'a` indicates a type variable that can be any type within the scope of the `log` function.
14347+
14348+Now, we can utilize the function obtained from `getLogger`:
14349+
14350+<CodeTab labels={["ReScript", "JS Output"]}>
14351+
14352+```res
14353+let myLogger = getLogger()
14354+
14355+myLogger.log("Hello, ReScript!")
14356+myLogger.log(42)
14357+```
14358+
14359+```js
14360+import * as JsAPI from "jsAPI";
14361+
14362+let myLogger = JsAPI.getLogger();
14363+
14364+myLogger.log("Hello, ReScript!");
14365+
14366+myLogger.log(42);
14367+
14368+export { myLogger };
14369+```
14370+
14371+</CodeTab>
14372+
14373+In this example, we create an instance of the logger by calling `getLogger()`, and then we can use the `log` function on the `myLogger` object to handle different data types.
14374+
14375+## Limitations of Normal Polymorphic Types
14376+
14377+Let's consider the same logging example in ReScript, but this time using normal polymorphic types:
14378+
14379+```res
14380+type logger<'a> = { log: 'a => unit}
14381+
14382+@module("jsAPI") external getLogger: unit => logger<'a> = "getLogger"
14383+```
14384+
14385+In this case, the `logger` type is a simple polymorphic function type `'a => unit`. However, when we attempt to use this type in the same way as before, we encounter an issue:
14386+
14387+```res
14388+let myLogger = getLogger()
14389+
14390+myLogger.log("Hello, ReScript!")
14391+myLogger.log(42) // Type error!
14392+```
14393+
14394+The problem arises because the type inference in ReScript assigns a concrete type to the `logger` function based on the first usage. In this example, after the first call to `myLogger`, the compiler infers the type `logger<string>` for `myLogger`. Consequently, when we attempt to pass an argument of type `number` in the next line, a type error occurs because it conflicts with the inferred type `logger<string>`.
14395+
14396+In contrast, scoped polymorphic types, such as `'a. 'a => unit`, overcome this limitation by allowing type variables within the scope of the function. They ensure that the type of the argument is preserved consistently within that scope, regardless of the specific value used in the first invocation.
14397+
14398+## Limitations of Scoped Polymorphic Types
14399+
14400+Scoped polymorphic types work only when they are directly applied to let-bindings or record fields (as demonstrated in the logger example above). They can neither be applied to function bodies, nor to separate type definitions:
14401+
14402+```res nocheck
14403+exception Abort
14404+
14405+let testExn: 'a. unit => 'a = () => throw(Abort) // Works!
14406+
14407+let testExn2 = (): 'a. 'a = throw(Abort) // Syntax error!
14408+type fn = 'a. 'a => unit // Syntax error!
14409+```
14410+
14411+---
14412+title: "Shared Data Types"
14413+description: "Data types that share runtime presentation between JS and ReScript"
14414+canonical: "/docs/manual/shared-data-types"
14415+section: "JavaScript Interop"
14416+order: 2
14417+---
14418+
14419+# Shared Data Types
14420+
14421+ReScript's built-in values of type `string`, `float`, `array` and a few others have a rather interesting property: they compile to the exact same value in JavaScript!
14422+
14423+This means that if you're passing e.g. a ReScript string to the JavaScript side, the JavaScript side can directly use it as a native string. It also means that you can import a JavaScript string and use it as a native ReScript string.
14424+
14425+ReScript values compile to their JavaScript equivalents directly, so **no data converters are needed for most types**.
14426+
14427+**Shared, bidirectionally usable types**:
14428+
14429+- String. ReScript strings are JavaScript strings, vice-versa. (Caveat: only our backtick string `` `hello 👋 ${personName}` `` supports unicode and interpolation).
14430+- Float. ReScript floats are JavaScript numbers, vice-versa.
14431+- Array. Use the [Array API](/docs/manual/api/stdlib/array) for array operations.
14432+- Tuple. Compiles to an array at runtime. You can treat a fixed-sized, heterogenous JavaScript array as a ReScript tuple too.
14433+- Boolean.
14434+- Record. Record compiles to a JavaScript object. Therefore you can also treat JavaScript objects as records. If they're too dynamic, consider modeling them on the ReScript side as a hashmap/dictionary [`Dict`](/docs/manual/api/stdlib/dict) or a ReScript object.
14435+- Object. ReScript objects are JavaScript objects, vice-versa.
14436+- Function. They compile to clean JavaScript functions.
14437+- Module. ReScript files are considered top-level modules, and are compiled to JavaScript files 1 to 1. Nested modules are compiled to JavaScript objects.
14438+- Polymorphic variants.
14439+- Unit. The `unit` type, which has a single value `()`, compiles to `undefined` too. Likewise, you can treat an incoming `undefined` as `()` if that's the only value it'll ever be.
14440+
14441+**Types that are slightly different, but that you can still use from JavaScript**:
14442+
14443+- Int. **Ints are 32-bits**! Be careful, you can potentially treat them as JavaScript numbers and vice-versa, but if the number's large, then you better treat JavaScript numbers as floats. For example, we bind to `Date` using `float`s.
14444+- Option. The `option` type's `None` value compiles into `undefined`. The `Some` value, e.g. `Some(5)`, compiles to `5`. Likewise, you can treat an incoming `undefined` as `None`. **`null` isn't handled here**. If your JavaScript value can be `null`, use [Nullable](/docs/manual/api/stdlib/nullable) helpers.
14445+- Exception.
14446+- Variant. Check the compiled JavaScript output of variant to see its shape. We don't recommend exporting a ReScript variant for pure JavaScript usage, since they're harder to read as plain JavaScript code, but you can do it.
14447+- List, which is just a regular variant.
14448+
14449+**Non-shared types (aka internal types)**:
14450+
14451+- Character.
14452+- Int64.
14453+- Lazy values.
14454+- Everything else.
14455+
14456+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.
14457+
14458+These types require manual conversions if you want to export them for JavaScript consumption. For a seamless JavaScript/TypeScript integration experience, check out the [TypeScript Integration](./typescript-integration.mdx) page instead of doing conversions by hand.
14459+
14460+---
14461+title: "Tagged templates"
14462+description: "Using tagged templates in ReScript"
14463+canonical: "/docs/manual/tagged-templates"
14464+section: "Language Features"
14465+order: 23
14466+---
14467+
14468+# Tagged templates
14469+
14470+**Since 11.1**
14471+
14472+Tagged templates provide a special form of string interpolation, enabling the creation of template literals
14473+where placeholders aren't restricted to strings. Moreover, the resulting output isn't confined solely to
14474+strings either. You can take a look at the [JS documentation
14475+about tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates)
14476+to learn more about them.
14477+
14478+## Define a tag function
14479+
14480+Tag functions in ReScript have the following signature:
14481+
14482+```res sig
14483+let myTagFunction : (array<string>, array<'param>) => 'output
14484+```
14485+
14486+As you can see, you can have any type you want both for the placeholder array and for the output.
14487+
14488+Given how string interpolation works, you'll always have the following invariant:
14489+
14490+```res nocheck
14491+Array.length(strings) == Array.length(placeholder) + 1
14492+```
14493+
14494+Let's say you want to interpolate strings with all kind of builtin types and make it work inside React components,
14495+you can define the following tag function:
14496+
14497+<CodeTab labels={["ReScript", "JS Output"]}>
14498+
14499+```res prelude
14500+type params =
14501+ | I(int)
14502+ | F(float)
14503+ | S(string)
14504+ | Bool(bool)
14505+
14506+let s = (strings, parameters) => {
14507+ let text = Array.reduceWithIndex(parameters, Array.getUnsafe(strings, 0), (
14508+ acc,
14509+ param,
14510+ i,
14511+ ) => {
14512+ let s = Array.getUnsafe(strings, i + 1)
14513+ let p = switch param {
14514+ | I(i) => Int.toString(i)
14515+ | F(f) => Float.toString(f)
14516+ | S(s) => s
14517+ | Bool(true) => "true"
14518+ | Bool(false) => "false"
14519+ }
14520+ acc ++ p ++ s
14521+ })
14522+ React.string(text)
14523+}
14524+```
14525+
14526+```js
14527+import * as Core__Array from "./stdlib/core__Array.js";
14528+
14529+function s(strings, parameters) {
14530+ return Core__Array.reduceWithIndex(
14531+ parameters,
14532+ strings[0],
14533+ function (acc, param, i) {
14534+ var s = strings[(i + 1) | 0];
14535+ var p;
14536+ switch (param.TAG) {
14537+ case "I":
14538+ case "F":
14539+ p = param._0.toString();
14540+ break;
14541+ case "S":
14542+ p = param._0;
14543+ break;
14544+ case "Bool":
14545+ p = param._0 ? "true" : "false";
14546+ break;
14547+ }
14548+ return acc + p + s;
14549+ },
14550+ );
14551+}
14552+```
14553+
14554+</CodeTab>
14555+
14556+## Write tagged template literals
14557+
14558+Now that you have defined your tag function, you can use it this way:
14559+
14560+<CodeTab labels={["ReScript", "JS Output", "JSX Preserved Output"]}>
14561+
14562+```res
14563+module Greetings = {
14564+ @react.component
14565+ let make = (~name, ~age) => {
14566+ <div> {s`hello ${S(name)} you're ${I(age)} year old!`} </div>
14567+ }
14568+}
14569+```
14570+
14571+```js
14572+import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
14573+import * as JsxRuntime from "react/jsx-runtime";
14574+
14575+function s(strings, parameters) {
14576+ return Stdlib_Array.reduceWithIndex(
14577+ parameters,
14578+ strings[0],
14579+ (acc, param, i) => {
14580+ let s = strings[(i + 1) | 0];
14581+ let p;
14582+ switch (param.TAG) {
14583+ case "I":
14584+ case "F":
14585+ p = param._0.toString();
14586+ break;
14587+ case "S":
14588+ p = param._0;
14589+ break;
14590+ case "Bool":
14591+ p = param._0 ? "true" : "false";
14592+ break;
14593+ }
14594+ return acc + p + s;
14595+ },
14596+ );
14597+}
14598+
14599+function Example$Greetings(props) {
14600+ return JsxRuntime.jsx("div", {
14601+ children: s(
14602+ [`hello `, ` you're `, ` year old!`],
14603+ [
14604+ {
14605+ TAG: "S",
14606+ _0: props.name,
14607+ },
14608+ {
14609+ TAG: "I",
14610+ _0: props.age,
14611+ },
14612+ ],
14613+ ),
14614+ });
14615+}
14616+
14617+let Greetings = {
14618+ make: Example$Greetings,
14619+};
14620+
14621+export { s, Greetings };
14622+```
14623+
14624+```jsx
14625+import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
14626+import * as JsxRuntime from "react/jsx-runtime";
14627+
14628+function s(strings, parameters) {
14629+ return Stdlib_Array.reduceWithIndex(
14630+ parameters,
14631+ strings[0],
14632+ (acc, param, i) => {
14633+ let s = strings[(i + 1) | 0];
14634+ let p;
14635+ switch (param.TAG) {
14636+ case "I":
14637+ case "F":
14638+ p = param._0.toString();
14639+ break;
14640+ case "S":
14641+ p = param._0;
14642+ break;
14643+ case "Bool":
14644+ p = param._0 ? "true" : "false";
14645+ break;
14646+ }
14647+ return acc + p + s;
14648+ },
14649+ );
14650+}
14651+
14652+function Example$Greetings(props) {
14653+ return (
14654+ <div>
14655+ {s(
14656+ [`hello `, ` you're `, ` year old!`],
14657+ [
14658+ {
14659+ TAG: "S",
14660+ _0: props.name,
14661+ },
14662+ {
14663+ TAG: "I",
14664+ _0: props.age,
14665+ },
14666+ ],
14667+ )}
14668+ </div>
14669+ );
14670+}
14671+
14672+let Greetings = {
14673+ make: Example$Greetings,
14674+};
14675+
14676+export { s, Greetings };
14677+```
14678+
14679+</CodeTab>
14680+
14681+Pretty neat, isn't it? As you can see, it looks like any regular template literal but it accepts placeholders that are not strings
14682+and it outputs something that is not a string either, a `React.element` in this case.
14683+
14684+---
14685+title: "Try"
14686+description: "Try ReScript via Command Line"
14687+canonical: "/docs/manual/try"
14688+---
14689+
14690+## Try Online
14691+
14692+Our [Playground](/try) lets you try ReScript online, and comes with the [ReScript React bindings](../react/introduction.mdx) and the new [ReScript Core](https://github.com/rescript-association/rescript-core) standard library preinstalled.
14693+
14694+---
14695+title: "Tuple"
14696+description: "Tuple types and values in ReScript"
14697+canonical: "/docs/manual/tuple"
14698+section: "Language Features"
14699+order: 5
14700+---
14701+
14702+# Tuple
14703+
14704+Tuples are a ReScript-specific data structure that don't exist in JavaScript. They are:
14705+
14706+- immutable
14707+- ordered
14708+- fix-sized at creation time
14709+- heterogeneous (can contain different types of values)
14710+
14711+<CodeTab labels={["ReScript", "JS Output"]}>
14712+
14713+```res
14714+let ageAndName = (24, "Lil' ReScript")
14715+let my3dCoordinates = (20.0, 30.5, 100.0)
14716+```
14717+
14718+```js
14719+let ageAndName = [24, "Lil' ReScript"];
14720+
14721+let my3dCoordinates = [20.0, 30.5, 100.0];
14722+
14723+export { ageAndName, my3dCoordinates };
14724+```
14725+
14726+</CodeTab>
14727+
14728+Tuples' types can be used in type annotations as well. Tuple types visually resemble tuples values.
14729+
14730+<CodeTab labels={["ReScript", "JS Output"]}>
14731+
14732+```res prelude
14733+let ageAndName: (int, string) = (24, "Lil' ReScript")
14734+// a tuple type alias
14735+type coord3d = (float, float, float)
14736+let my3dCoordinates: coord3d = (20.0, 30.5, 100.0)
14737+```
14738+
14739+```js
14740+var ageAndName = [24, "Lil' ReScript"];
14741+var my3dCoordinates = [20.0, 30.5, 100.0];
14742+```
14743+
14744+</CodeTab>
14745+
14746+**Note**: there's no tuple of size 1. You'd just use the value itself.
14747+
14748+## Usage
14749+
14750+To get a specific member of a tuple, destructure it:
14751+
14752+<CodeTab labels={["ReScript", "JS Output"]}>
14753+
14754+```res
14755+let (_, y, _) = my3dCoordinates // now you've retrieved y
14756+```
14757+
14758+```js
14759+let ageAndName = [24, "Lil' ReScript"];
14760+
14761+let my3dCoordinates = [20.0, 30.5, 100.0];
14762+
14763+let y = 30.5;
14764+
14765+export { ageAndName, my3dCoordinates, y };
14766+```
14767+
14768+</CodeTab>
14769+
14770+The `_` means you're ignoring the indicated members of the tuple.
14771+
14772+Tuples aren't meant to be updated mutatively. You'd create new ones by destructuring the old ones:
14773+
14774+<CodeTab labels={["ReScript", "JS Output"]}>
14775+
14776+```res
14777+let coordinates1 = (10, 20, 30)
14778+let (c1x, _, _) = coordinates1
14779+let coordinates2 = (c1x + 50, 20, 30)
14780+```
14781+
14782+```js
14783+let coordinates2 = [60, 20, 30];
14784+
14785+let ageAndName = [24, "Lil' ReScript"];
14786+
14787+let my3dCoordinates = [20.0, 30.5, 100.0];
14788+
14789+let coordinates1 = [10, 20, 30];
14790+
14791+let c1x = 10;
14792+
14793+export { ageAndName, my3dCoordinates, coordinates1, c1x, coordinates2 };
14794+```
14795+
14796+</CodeTab>
14797+
14798+## Tips & Tricks
14799+
14800+You'd use tuples in handy situations that pass around multiple values without too much ceremony. For example, to return many values:
14801+
14802+<CodeTab labels={["ReScript", "JS Output"]}>
14803+
14804+```res nocheck
14805+let getCenterCoordinates = () => {
14806+ let x = doSomeOperationsHere()
14807+ let y = doSomeMoreOperationsHere()
14808+ (x, y)
14809+}
14810+```
14811+
14812+```js
14813+function getCenterCoordinates(param) {
14814+ var x = doSomeOperationsHere(undefined);
14815+ var y = doSomeMoreOperationsHere(undefined);
14816+ return [x, y];
14817+}
14818+```
14819+
14820+</CodeTab>
14821+
14822+Try to keep the usage of tuple **local**. For data structures that are long-living and passed around often, prefer a **record**, which has named fields.
14823+
14824+---
14825+title: "Type"
14826+description: "Types and type definitions in ReScript"
14827+canonical: "/docs/manual/type"
14828+section: "Language Features"
14829+order: 3
14830+---
14831+
14832+# Type
14833+
14834+Types are the highlight of ReScript! They are:
14835+
14836+- **Strong**. A type can't change into another type. In JavaScript, your variable's type might change when the code runs (aka at runtime). E.g. a `number` variable might change into a `string` sometimes. This is an anti-feature; it makes the code much harder to understand when reading or debugging.
14837+- **Static**. ReScript types are erased after compilation and don't exist at runtime. Never worry about your types dragging down performance. You don't need type info during runtime; we report all the information (especially all the type errors) during compile time. Catch the bugs earlier!
14838+- **Sound**. This is our biggest differentiator versus many other typed languages that compile to JavaScript. Our type system is guaranteed to **never** be wrong. Most type systems make a guess at the type of a value and show you a type in your editor that's sometime incorrect. We don't do that. We believe that a type system that is sometime incorrect can end up being dangerous due to expectation mismatches.
14839+- **Fast**. Many developers underestimate how much of their project's build time goes into type checking. Our type checker is one of the fastest around.
14840+- **Inferred**. You don't have to write down the types! ReScript can deduce them from their values. Yes, it might seem magical that we can deduce all of your program's types, without incorrectness, without your manual annotation, and do so quickly. Welcome to ReScript =).
14841+
14842+The following sections explore more of our type system.
14843+
14844+## Inference
14845+
14846+This let-binding doesn't contain any written type:
14847+
14848+<CodeTab labels={["ReScript", "JS Output"]}>
14849+
14850+```res
14851+let score = 10
14852+let add = (a, b) => a + b
14853+```
14854+
14855+```js
14856+function add(a, b) {
14857+ return (a + b) | 0;
14858+}
14859+
14860+let score = 10;
14861+
14862+export { score, add };
14863+```
14864+
14865+</CodeTab>
14866+
14867+ReScript knows that `score` is an `int`, judging by the value `10`. This is called **inference**. Likewise, it also knows that the `add` function takes 2 `int`s and returns an `int`, judging from the `+` operator, which works on ints.
14868+
14869+## Type Annotation
14870+
14871+But you can also optionally write down the type, aka annotate your value:
14872+
14873+<CodeTab labels={["ReScript", "JS Output"]}>
14874+
14875+```res
14876+let score: int = 10
14877+```
14878+
14879+```js
14880+let score = 10;
14881+
14882+export { score };
14883+```
14884+
14885+</CodeTab>
14886+
14887+If the type annotation for `score` doesn't correspond to our inferred type for it, we'll show you an error during compilation time. We **won't** silently assume your type annotation is correct, unlike many other languages.
14888+
14889+You can also wrap any expression in parentheses and annotate it:
14890+
14891+<CodeTab labels={["ReScript", "JS Output"]}>
14892+
14893+```res nocheck
14894+let myInt = 5
14895+let myInt: int = 5
14896+let myInt = (5: int) + (4: int)
14897+let add = (x: int, y: int) : int => x + y
14898+let drawCircle = (~radius as r: int): circleType => /* code here */
14899+```
14900+
14901+```js
14902+var myInt = 9;
14903+function add(x, y) {
14904+ return (x + y) | 0;
14905+}
14906+function drawCircle(r) {
14907+ /* code here */
14908+}
14909+```
14910+
14911+</CodeTab>
14912+
14913+Note: in the last line, `(~radius as r: int)` is a labeled argument. More on this in the [function](./function.mdx) page.
14914+
14915+## Type Alias
14916+
14917+You can refer to a type by a different name. They'll be equivalent:
14918+
14919+<CodeTab labels={["ReScript", "JS Output"]}>
14920+
14921+```res
14922+type scoreType = int
14923+let x: scoreType = 10
14924+```
14925+
14926+```js
14927+let x = 10;
14928+
14929+export { x };
14930+```
14931+
14932+</CodeTab>
14933+
14934+## Type Parameter (Aka Generic)
14935+
14936+Types can accept parameters, akin to generics in other languages. The parameters' names **need** to start with `'`.
14937+
14938+The use-case of a parameterized type is to kill duplications. Before:
14939+
14940+<CodeTab labels={["ReScript", "JS Output"]}>
14941+
14942+```res
14943+// this is a tuple of 3 items, explained next
14944+type intCoordinates = (int, int, int)
14945+type floatCoordinates = (float, float, float)
14946+
14947+let a: intCoordinates = (10, 20, 20)
14948+let b: floatCoordinates = (10.5, 20.5, 20.5)
14949+```
14950+
14951+```js
14952+let a = [10, 20, 20];
14953+
14954+let b = [10.5, 20.5, 20.5];
14955+
14956+export { a, b };
14957+```
14958+
14959+</CodeTab>
14960+
14961+After:
14962+
14963+<CodeTab labels={["ReScript", "JS Output"]}>
14964+
14965+```res
14966+type coordinates<'a> = ('a, 'a, 'a)
14967+
14968+let a: coordinates<int> = (10, 20, 20)
14969+let b: coordinates<float> = (10.5, 20.5, 20.5)
14970+```
14971+
14972+```js
14973+let a = [10, 20, 20];
14974+
14975+let b = [10.5, 20.5, 20.5];
14976+
14977+export { a, b };
14978+```
14979+
14980+</CodeTab>
14981+
14982+Note that the above codes are just contrived examples for illustration purposes. Since the types are inferred, you could have just written:
14983+
14984+<CodeTab labels={["ReScript", "JS Output"]}>
14985+
14986+```res
14987+let buddy = (10, 20, 20)
14988+```
14989+
14990+```js
14991+let buddy = [10, 20, 20];
14992+
14993+export { buddy };
14994+```
14995+
14996+</CodeTab>
14997+
14998+The type system infers that it's a `(int, int, int)`. Nothing else needed to be written down.
14999+
15000+Type arguments appear in many places. Our `array<'a>` type is such a type that requires a type parameter.
15001+
15002+<CodeTab labels={["ReScript", "JS Output"]}>
15003+
15004+```res
15005+// inferred as `array<string>`
15006+let greetings = ["hello", "world", "how are you"]
15007+```
15008+
15009+```js
15010+let greetings = ["hello", "world", "how are you"];
15011+
15012+export { greetings };
15013+```
15014+
15015+</CodeTab>
15016+
15017+If types didn't accept parameters, the standard library would need to define the types `arrayOfString`, `arrayOfInt`, `arrayOfTuplesOfInt`, etc. That'd be tedious.
15018+
15019+Types can receive many arguments, and be composable.
15020+
15021+{/* TODO: too early for this example */}
15022+
15023+<CodeTab labels={["ReScript", "JS Output"]}>
15024+
15025+```res
15026+type result<'a, 'b> =
15027+ | Ok('a)
15028+ | Error('b)
15029+
15030+type myPayload = {data: string}
15031+
15032+type myPayloadResults<'errorType> = array<result<myPayload, 'errorType>>
15033+
15034+let payloadResults: myPayloadResults<string> = [
15035+ Ok({data: "hi"}),
15036+ Ok({data: "bye"}),
15037+ Error("Something wrong happened!")
15038+]
15039+```
15040+
15041+```js
15042+let payloadResults = [
15043+ {
15044+ TAG: "Ok",
15045+ _0: {
15046+ data: "hi",
15047+ },
15048+ },
15049+ {
15050+ TAG: "Ok",
15051+ _0: {
15052+ data: "bye",
15053+ },
15054+ },
15055+ {
15056+ TAG: "Error",
15057+ _0: "Something wrong happened!",
15058+ },
15059+];
15060+
15061+export { payloadResults };
15062+```
15063+
15064+</CodeTab>
15065+
15066+## Recursive Types
15067+
15068+Just like a function, a type can reference itself within itself using `rec`:
15069+
15070+<CodeTab labels={["ReScript", "JS Output"]}>
15071+
15072+```res
15073+type rec person = {
15074+ name: string,
15075+ friends: array<person>
15076+}
15077+```
15078+
15079+```js
15080+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
15081+```
15082+
15083+</CodeTab>
15084+
15085+## Mutually Recursive Types
15086+
15087+Types can also be _mutually_ recursive through `and`:
15088+
15089+<CodeTab labels={["ReScript", "JS Output"]}>
15090+
15091+```res
15092+type rec student = {taughtBy: teacher}
15093+and teacher = {students: array<student>}
15094+```
15095+
15096+```js
15097+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
15098+```
15099+
15100+</CodeTab>
15101+
15102+## Type Escape Hatch
15103+
15104+ReScript's type system is robust and does not allow dangerous, unsafe stuff like implicit type casting, randomly guessing a value's type, etc. However, out of pragmatism, we expose a single escape hatch for you to "lie" to the type system:
15105+
15106+<CodeTab labels={["ReScript", "JS Output"]}>
15107+
15108+```res nocheck
15109+external myShadyConversion: myType1 => myType2 = "%identity"
15110+```
15111+
15112+```js
15113+// Empty output
15114+```
15115+
15116+</CodeTab>
15117+
15118+This declaration converts a `myType1` of your choice to `myType2` of your choice. You can use it like so:
15119+
15120+<CodeTab labels={["ReScript", "JS Output"]}>
15121+
15122+```res
15123+external convertToFloat : int => float = "%identity"
15124+let age = 10
15125+let gpa = 2.1 + convertToFloat(age)
15126+```
15127+
15128+```js
15129+let gpa = 2.1 + 10;
15130+
15131+let age = 10;
15132+
15133+export { age, gpa };
15134+```
15135+
15136+</CodeTab>
15137+
15138+Obviously, do **not** abuse this feature. Use it tastefully when you're working with existing, overly dynamic JS code, for example.
15139+
15140+More on externals [here](./external.mdx).
15141+
15142+**Note**: this particular `external` is the only one that isn't preceded by a `@` [attribute](./attribute.mdx).
15143+
15144+---
15145+title: "TypeScript"
15146+description: "GenType - Interoperability between ReScript and TypeScript"
15147+canonical: "/docs/manual/typescript-integration"
15148+section: "JavaScript Interop"
15149+order: 15
15150+---
15151+
15152+# ReScript & TypeScript
15153+
15154+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".
15155+
15156+The implementation of genType performs a type-directed transformation of ReScript programs after compilation. The transformed programs operate on data types idiomatic to TypeScript.
15157+
15158+For example, a ReScript variant (which is represented as custom objects with tags at runtime):
15159+
15160+```res
15161+@genType
15162+type t = | A(int) | B(string)
15163+```
15164+
15165+is exported to a TypeScript type:
15166+
15167+```ts
15168+type t = { TAG: "A"; _0: number } | { TAG: "B"; _0: string };
15169+```
15170+
15171+## A Quick Example
15172+
15173+Let's assume we are working on a TypeScript codebase and we want to integrate a single ReScript function.
15174+
15175+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.
15176+
15177+**That's exactly what genType was made for!**
15178+
15179+First we'll set up a function:
15180+
15181+```res
15182+// src/Color.res
15183+
15184+@genType
15185+type color =
15186+ | Red
15187+ | Blue
15188+
15189+@genType
15190+let printColorMessage = (~color, ~message) => {
15191+ let prefix = switch color {
15192+ | Red => "\x1b[91m"
15193+ | Blue => "\x1b[94m"
15194+ }
15195+ let reset = "\x1b[0m"
15196+
15197+ Console.log(prefix ++ message ++ reset)
15198+}
15199+
15200+```
15201+
15202+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:
15203+
15204+```ts
15205+// src/Color.gen.tsx
15206+
15207+/* TypeScript file generated from Color.res by genType. */
15208+
15209+/* eslint-disable */
15210+/* tslint:disable */
15211+
15212+import * as ColorJS from "./Color.res.js";
15213+
15214+export type color = "Red" | "Blue";
15215+
15216+export const printColorMessage: (color: color) => void =
15217+ ColorJS.printColorMessage as any;
15218+```
15219+
15220+genType automatically maps the `color` variant to TS via a string union type `"Red" | "Blue"`.
15221+
15222+Within our TypeScript application, we can now import and use the function in the following manner:
15223+
15224+```ts
15225+// src/app.ts
15226+
15227+import { printColorMessage } from "./Color.gen.tsx";
15228+
15229+printColorMessage("Red", "Hello, genType!");
15230+```
15231+
15232+## Exporting an entire module
15233+
15234+_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:
15235+
15236+<CodeTab labels={["ReScript", "TypeScript Output"]}>
15237+
15238+```res
15239+@genType
15240+module Size = {
15241+ type t =
15242+ | Small
15243+ | Medium
15244+ | Large
15245+
15246+ let getNum = (size: t) =>
15247+ switch size {
15248+ | Small => 1.
15249+ | Medium => 5.
15250+ | Large => 10.
15251+ }
15252+}
15253+```
15254+
15255+```ts
15256+import * as MyCompBS__Es6Import from "./MyComp.res";
15257+const MyCompBS: any = MyCompBS__Es6Import;
15258+
15259+export type Size_t = "Small" | "Medium" | "Large";
15260+
15261+export const Size_getNum: (size: Size_t) => number = MyCompBS.Size.getNum;
15262+
15263+export const Size: { getNum: (size: Size_t) => number } = MyCompBS.Size;
15264+```
15265+
15266+```js
15267+function getNum(size) {
15268+ switch (size) {
15269+ case "Small":
15270+ return 1;
15271+ case "Medium":
15272+ return 5;
15273+ case "Large":
15274+ return 10;
15275+ }
15276+}
15277+
15278+let Size = {
15279+ getNum: getNum,
15280+};
15281+
15282+export { Size };
15283+```
15284+
15285+</CodeTab>
15286+
15287+## Setup
15288+
15289+Add a `gentypeconfig` section to your `rescript.json` (See [Configuration](./build-configuration.mdx#gentypeconfig) for details).
15290+
15291+Every `genType` powered project requires a configuration item `"gentypeconfig"` at top level in the project's `rescript.json`.
15292+
15293+The minimal configuration of genType is following:
15294+
15295+```json
15296+{
15297+ "gentypeconfig": {
15298+ "module": "esmodule",
15299+ "moduleResolution": "node",
15300+ "generatedFileExtension": ".gen.tsx"
15301+ }
15302+}
15303+```
15304+
15305+And don't forget to make sure `allowJs` is set to `true` in the project's `tsconfig.json`:
15306+
15307+```json
15308+{
15309+ "compilerOptions": {
15310+ "allowJs": true
15311+ }
15312+}
15313+```
15314+
15315+### TypeScript Module Resolutions
15316+
15317+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.
15318+
15319+For example if the TypeScript project uses JavaScript modules with `Node16` / `NodeNext` module resolution:
15320+
15321+```json
15322+// tsconfig.json
15323+{
15324+ "compilerOptions": {
15325+ "moduleResolution": "node16"
15326+ }
15327+}
15328+```
15329+
15330+Then `moduleResolution` in `gentypeconfig` should be same value:
15331+
15332+```json
15333+// rescript.json
15334+{
15335+ "gentypeconfig": {
15336+ "moduleResolution": "node16"
15337+ }
15338+}
15339+```
15340+
15341+In case of the TypeScript project using `Bundler` module resolution, `allowImportingTsExtensions` should also be `true`:
15342+
15343+```json
15344+// tsconfig.json
15345+{
15346+ "compilerOptions": {
15347+ "moduleResolution": "bundler",
15348+ "allowImportingTsExtensions": true
15349+ }
15350+}
15351+```
15352+
15353+```json
15354+// rescript.json
15355+{
15356+ "gentypeconfig": {
15357+ "moduleResolution": "bundler"
15358+ }
15359+}
15360+```
15361+
15362+## Testing the Whole Setup
15363+
15364+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).
15365+
15366+Save the file and rebuild the project via `npm run build:res` or similar. You should now see a `*.gen.tsx` file with the same name (e.g. `MyComponent.res` -> `MyComponent.gen.tsx`).
15367+
15368+Any values exported from `MyComponent.res` can then be imported from TypeScript. For example:
15369+
15370+```js
15371+import MyComponent from "./components/MyComponent.gen.tsx";
15372+```
15373+
15374+## Experimental features
15375+
15376+These features are for experimentation only. They could be changed/removed any time, and not be considered breaking changes.
15377+
15378+- Export object and record types as interfaces. To activate, add `"exportInterfaces": true` to the configuration. The types are also renamed from `name` to `Iname`.
15379+
15380+## Shims
15381+
15382+A shim is a TS file that provides user-provided definitions for library types.
15383+
15384+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.
15385+
15386+- Example: `Array<string>` with format: `"RescriptModule=JavaScriptModule"`
15387+
15388+Configure your shim files within `"gentypeconfig"` in your [`rescript.json`]:
15389+
15390+```json
15391+{
15392+ "gentypeconfig": {
15393+ "shims": {
15394+ "Js": "Js",
15395+ "ReactEvent": "ReactEvent",
15396+ "RescriptPervasives": "RescriptPervasives",
15397+ "ReasonReact": "ReactShim"
15398+ }
15399+ }
15400+}
15401+```
15402+
15403+and add relevant `.shim.ts` files in a directory which is visible by ReScript e.g.
15404+
15405+```
15406+├── rescript.json
15407+├── src
15408+│ ├── shims
15409+│ │ ├── Js.shim.ts
15410+│ │ ├── ReactEvent.shim.ts
15411+│ │ └── RescriptPervasives.shim.ts
15412+```
15413+
15414+Here are some examples:
15415+
15416+```ts
15417+// Excerpt from https://github.com/rescript-lang/rescript-compiler/blob/master/jscomp/gentype_tests/typescript-react-example/src/shims/Js.shim.ts
15418+export type Json_t = unknown;
15419+export type t = unknown;
15420+```
15421+
15422+```ts
15423+// Excerpt from https://github.com/rescript-lang/rescript-compiler/tree/master/jscomp/gentype_tests/typescript-react-example/src/shims
15424+export type inputFocusEvent = React.FocusEvent<HTMLInputElement>;
15425+```
15426+
15427+More complete example shims can be found [here](https://github.com/rescript-lang/rescript-compiler/blob/master/jscomp/gentype_tests/typescript-react-example/src/shims/).
15428+
15429+## Deprecated features
15430+
15431+Features related to generating runtimes were deprecated since v11 and should no longer be used.
15432+
15433+- **`@genType("alias")`** and **`@genType.as("alias")`**
15434+- **`@genType.opaque`**
15435+- **`@genType.import`**
15436+- TypeScript Shims
15437+
15438+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)).
15439+
15440+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.
15441+
15442+## Limitations
15443+
15444+- **in-source = true**. Currently only supports ReScript projects with [in-source generation](./build-configuration.mdx#package-specs) and file suffixes that end on `.js`, like `.res.js` or `.bs.js`.
15445+
15446+- **Limited namespace support**. Currently there's limited [namespace](./build-configuration.mdx#name-namespace) support, and only `namespace:true` is possible, not e.g. `namespace:"custom"`.
15447+
15448+---
15449+title: "Use Illegal Identifier Names"
15450+description: "Handling (JS) naming collisions in ReScript"
15451+canonical: "/docs/manual/use-illegal-identifier-names"
15452+section: "JavaScript Interop"
15453+order: 11
15454+---
15455+
15456+# Use Illegal Identifier Names
15457+
15458+Sometime, for e.g. a let binding or a record field, you might want to use:
15459+
15460+- A capitalized name.
15461+- A name that contains illegal characters (e.g. emojis, hyphen, space).
15462+- A name that's one of ReScript's reserved keywords.
15463+
15464+We provide an escape hatch syntax for these cases:
15465+
15466+<CodeTab labels={["ReScript", "JS Output"]}>
15467+
15468+```res
15469+let \"my-🍎" = 10
15470+
15471+type element = {
15472+ \"aria-label": string
15473+}
15474+
15475+let myElement = {
15476+ \"aria-label": "close"
15477+}
15478+
15479+let label = myElement.\"aria-label"
15480+
15481+let calculate = (~\"Props") => {
15482+ \"Props" + 1
15483+}
15484+```
15485+
15486+```js
15487+function calculate(Props) {
15488+ return (Props + 1) | 0;
15489+}
15490+
15491+let my$$unknown$unknown$unknown$unknown = 10;
15492+
15493+let myElement = {
15494+ "aria-label": "close",
15495+};
15496+
15497+let label = "close";
15498+
15499+export { my$$unknown$unknown$unknown$unknown, myElement, label, calculate };
15500+```
15501+
15502+</CodeTab>
15503+
15504+See the output. **Use them only when necessary**, for interop with JavaScript. This is a last-resort feature. If you abuse this, many of the compiler guarantees will go away.
15505+
15506+---
15507+title: "Variant"
15508+description: "Variant data structures in ReScript"
15509+canonical: "/docs/manual/variant"
15510+section: "Language Features"
15511+order: 9
15512+---
15513+
15514+# Variant
15515+
15516+So far, most of ReScript's data structures might look familiar to you. This section introduces an extremely important, and perhaps unfamiliar, data structure: variant.
15517+
15518+Most data structures in most languages are about "this **and** that". A variant allows us to express "this **or** that".
15519+
15520+<CodeTab labels={["ReScript", "JS Output"]}>
15521+
15522+```res
15523+type myResponse =
15524+ | Yes
15525+ | No
15526+ | PrettyMuch
15527+
15528+let areYouCrushingIt = Yes
15529+```
15530+
15531+```js
15532+let areYouCrushingIt = "Yes";
15533+
15534+export { areYouCrushingIt };
15535+```
15536+
15537+</CodeTab>
15538+
15539+`myResponse` is a variant type with the cases `Yes`, `No` and `PrettyMuch`, which are called "variant constructors" (or "variant tag"). The `|` bar separates each constructor.
15540+
15541+**Note**: a variant's constructors need to be capitalized.
15542+
15543+## Variant Needs an Explicit Definition
15544+
15545+If the variant you're using is in a different file, bring it into scope [record](./record.mdx) type
15546+
15547+<CodeTab labels={["ReScript", "JS Output"]}>
15548+
15549+```res
15550+// Zoo.res
15551+type animal = Dog | Cat | Bird
15552+```
15553+
15554+```js
15555+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
15556+```
15557+
15558+</CodeTab>
15559+
15560+<CodeTab labels={["ReScript", "JS Output"]}>
15561+
15562+```res nocheck
15563+// Example.res
15564+let pet: Zoo.animal = Dog // preferred
15565+// or
15566+let pet2 = Zoo.Dog
15567+```
15568+
15569+```js
15570+var pet = "Dog";
15571+var pet2 = "Dog";
15572+```
15573+
15574+</CodeTab>
15575+
15576+## Constructor Arguments
15577+
15578+A variant's constructors can hold extra data separated by comma.
15579+
15580+<CodeTab labels={["ReScript", "JS Output"]}>
15581+
15582+```res prelude
15583+type account =
15584+ | None
15585+ | Instagram(string)
15586+ | Facebook(string, int)
15587+```
15588+
15589+```js
15590+// Empty output
15591+```
15592+
15593+</CodeTab>
15594+
15595+Here, `Instagram` holds a `string`, and `Facebook` holds a `string` and an `int`. Usage:
15596+
15597+<CodeTab labels={["ReScript", "JS Output"]}>
15598+
15599+```res
15600+let myAccount = Facebook("Josh", 26)
15601+let friendAccount = Instagram("Jenny")
15602+```
15603+
15604+```js
15605+let myAccount = {
15606+ TAG: "Facebook",
15607+ _0: "Josh",
15608+ _1: 26,
15609+};
15610+
15611+let friendAccount = {
15612+ TAG: "Instagram",
15613+ _0: "Jenny",
15614+};
15615+
15616+export { myAccount, friendAccount };
15617+```
15618+
15619+</CodeTab>
15620+
15621+### Labeled Variant Payloads (Inline Record)
15622+
15623+If a variant payload has multiple fields, you can use a record-like syntax to label them for better readability:
15624+
15625+<CodeTab labels={["ReScript", "JS Output"]}>
15626+
15627+```res
15628+type user =
15629+ | Number(int)
15630+ | Id({name: string, password: string})
15631+
15632+let me = Id({name: "Joe", password: "123"})
15633+```
15634+
15635+```js
15636+let me = {
15637+ TAG: "Id",
15638+ name: "Joe",
15639+ password: "123",
15640+};
15641+
15642+export { me };
15643+```
15644+
15645+</CodeTab>
15646+
15647+This is technically called an "inline record", and only allowed within a variant constructor. You cannot inline a record type declaration anywhere else in ReScript.
15648+
15649+Of course, you can just put a regular record type in a variant too:
15650+
15651+<CodeTab labels={["ReScript", "JS Output"]}>
15652+
15653+```res
15654+type u = {name: string, password: string}
15655+type user =
15656+ | Number(int)
15657+ | Id(u)
15658+
15659+let me = Id({name: "Joe", password: "123"})
15660+```
15661+
15662+```js
15663+let me = {
15664+ TAG: "Id",
15665+ _0: {
15666+ name: "Joe",
15667+ password: "123",
15668+ },
15669+};
15670+
15671+export { me };
15672+```
15673+
15674+</CodeTab>
15675+
15676+The output is slightly uglier and less performant than the former.
15677+
15678+## Variant Type Spreads
15679+
15680+Just like [with records](./record.mdx#record-type-spread), it's possible to use type spreads to create new variants from other variants:
15681+
15682+```rescript
15683+type a = One | Two | Three
15684+type b = | ...a | Four | Five
15685+```
15686+
15687+Type `b` is now:
15688+
15689+```rescript
15690+type b = One | Two | Three | Four | Five
15691+```
15692+
15693+Type spreads act as a 'copy-paste', meaning all constructors are copied as-is from `a` to `b`. Here are the rules for spreads to work:
15694+
15695+- You can't overwrite constructors, so the same constructor name can exist in only one place as you spread. This is true even if the constructors are identical.
15696+- All variants and constructors must share the same runtime configuration - `@unboxed`, `@tag`, `@as` and so on.
15697+- You can't spread types in recursive definitions.
15698+
15699+Note that you need a leading `|` if you want to use a spread in the first position of a variant definition.
15700+
15701+### Pattern Matching On Variant
15702+
15703+See the [Pattern Matching/Destructuring](./pattern-matching-destructuring.mdx) section later.
15704+
15705+## JavaScript Output
15706+
15707+A variant value compiles to 3 possible JavaScript outputs depending on its type declaration:
15708+
15709+- If the variant value is a constructor with no payload, it compiles to a string of the constructor name. Example: `Yes` compiles to `"Yes"`.
15710+- If it's a constructor with a payload, it compiles to an object with the field `TAG` and the field `_0` for the first payload, `_1` for the second payload, etc. The value of `TAG` is the constructor name as string by default, but note that the name of the `TAG` field as well as the string value used for each constructor name [can be customized](#tagged-variants).
15711+- Labeled variant payloads (the inline record trick earlier) compile to an object with the label names instead of `_0`, `_1`, etc. The object will have the `TAG` field as per the previous rule.
15712+
15713+Check the output in these examples:
15714+
15715+<CodeTab labels={["ReScript", "JS Output"]}>
15716+
15717+```res
15718+type greeting = Hello | Goodbye
15719+let g1 = Hello
15720+let g2 = Goodbye
15721+
15722+type outcome = Good | Error(string)
15723+let o1 = Good
15724+let o2 = Error("oops!")
15725+
15726+type family = Child | Mom(int, string) | Dad (int)
15727+let f1 = Child
15728+let f2 = Mom(30, "Jane")
15729+let f3 = Dad(32)
15730+
15731+type person = Teacher | Student({gpa: float})
15732+let p1 = Teacher
15733+let p2 = Student({gpa: 99.5})
15734+
15735+type s = {score: float}
15736+type adventurer = Warrior(s) | Wizard(string)
15737+let a1 = Warrior({score: 10.5})
15738+let a2 = Wizard("Joe")
15739+```
15740+
15741+```js
15742+let g1 = "Hello";
15743+
15744+let g2 = "Goodbye";
15745+
15746+let o1 = "Good";
15747+
15748+let o2 = {
15749+ TAG: "Error",
15750+ _0: "oops!",
15751+};
15752+
15753+let f1 = "Child";
15754+
15755+let f2 = {
15756+ TAG: "Mom",
15757+ _0: 30,
15758+ _1: "Jane",
15759+};
15760+
15761+let f3 = {
15762+ TAG: "Dad",
15763+ _0: 32,
15764+};
15765+
15766+let p1 = "Teacher";
15767+
15768+let p2 = {
15769+ TAG: "Student",
15770+ gpa: 99.5,
15771+};
15772+
15773+let a1 = {
15774+ TAG: "Warrior",
15775+ _0: {
15776+ score: 10.5,
15777+ },
15778+};
15779+
15780+let a2 = {
15781+ TAG: "Wizard",
15782+ _0: "Joe",
15783+};
15784+
15785+export { g1, g2, o1, o2, f1, f2, f3, p1, p2, a1, a2 };
15786+```
15787+
15788+</CodeTab>
15789+
15790+## Tagged variants
15791+
15792+- The `@tag` attribute lets you customize the discriminator (default: `TAG`).
15793+- `@as` attributes control what each variant case is discriminated on (default: the variant case name as string).
15794+
15795+### Example: Binding to TypeScript enums
15796+
15797+```typescript
15798+// direction.ts
15799+/** Direction of the action. */
15800+enum Direction {
15801+ /** The direction is up. */
15802+ Up = "UP",
15803+
15804+ /** The direction is down. */
15805+ Down = "DOWN",
15806+
15807+ /** The direction is left. */
15808+ Left = "LEFT",
15809+
15810+ /** The direction is right. */
15811+ Right = "RIGHT",
15812+}
15813+
15814+export const myDirection = Direction.Up;
15815+```
15816+
15817+You can bind to the above enums like so:
15818+
15819+```rescript
15820+/** Direction of the action. */
15821+type direction =
15822+ | /** The direction is up. */
15823+ @as("UP")
15824+ Up
15825+
15826+ | /** The direction is down. */
15827+ @as("DOWN")
15828+ Down
15829+
15830+ | /** The direction is left. */
15831+ @as("LEFT")
15832+ Left
15833+
15834+ | /** The direction is right. */
15835+ @as("RIGHT")
15836+ Right
15837+
15838+@module("./direction.js") external myDirection: direction = "myDirection"
15839+```
15840+
15841+Now, this maps 100% to the TypeScript code, including letting us bring over the documentation strings so we get a nice editor experience.
15842+
15843+### String literals
15844+
15845+The same logic is easily applied to string literals from TypeScript, only here the benefit is even larger, because string literals have the same limitations in TypeScript that polymorphic variants have in ReScript:
15846+
15847+```typescript
15848+// direction.ts
15849+type direction = "UP" | "DOWN" | "LEFT" | "RIGHT";
15850+```
15851+
15852+There's no way to attach documentation strings to string literals in TypeScript, and you only get the actual value to interact with.
15853+
15854+### Valid `@as` payloads
15855+
15856+Here's a list of everything you can put in the `@as` tag of a variant constructor:
15857+
15858+- A string literal: `@as("success")`
15859+- An int: `@as(5)`
15860+- A float: `@as(1.5)`
15861+- True/false: `@as(true)` and `@as(false)`
15862+- Null: `@as(null)`
15863+- Undefined: `@as(undefined)`
15864+
15865+## Untagged variants
15866+
15867+With _untagged variants_ it is possible to mix types together that normally can't be mixed in the ReScript type system, as long as there's a way to discriminate them at runtime. For example, with untagged variants you can represent a heterogenous array:
15868+
15869+```rescript
15870+@unboxed type listItemValue = String(string) | Boolean(bool) | Number(float)
15871+
15872+let myArray = [String("Hello"), Boolean(true), Boolean(false), Number(13.37)]
15873+```
15874+
15875+Here, each value will be _unboxed_ at runtime. That means that the variant payload will be all that's left, the variant case name wrapping the payload itself will be stripped out and the payload will be all that remains.
15876+
15877+It, therefore, compiles to this JS:
15878+
15879+```javascript
15880+var myArray = ["hello", true, false, 13.37];
15881+```
15882+
15883+In the above example, reaching back into the values is as simple as pattern matching on them.
15884+
15885+### Advanced: Unboxing rules
15886+
15887+#### No overlap in constructors
15888+
15889+A variant can be unboxed if no constructors have overlap in their runtime representation.
15890+
15891+For example, you can't have `String1(string) | String2(string)` in the same unboxed variant, because there's no way for ReScript to know at runtime which of `String1` or `String2` that `string` belongs to, as it could belong to both.
15892+The same goes for two records - even if they have fully different shapes, they're still JavaScript `object` at runtime.
15893+
15894+Don't worry - the compiler will guide you and ensure there's no overlap.
15895+
15896+#### What you can unbox
15897+
15898+Here's a list of all possible things you can unbox:
15899+
15900+- `string`: `String(string)`
15901+- `float`: `Float(float)`. Note you can only have one of `float` or `int` because JavaScript only has `number` (not actually `int` and `float` like in ReScript) so we can't disambiguate between `float` and `int` at runtime.
15902+- `int`: `Int(int)`. See note above on `float`.
15903+- `bigint`: `BigInt(int)`. **Since 11.1** This is a distinct type from JavaScript's `number` type so you can use it beside either `float` or `int`.
15904+- `bool`: `Boolean(bool)`
15905+- `array<'value>`: `List(array<string>)`
15906+- `('a, 'b, 'c)`: `Tuple((string, int, bool))`. Any size of tuples works, but you can have only one case of array or tuple in a variant.
15907+- `promise<'value>`: `Promise(promise<string>)`
15908+- `Dict.t`: `Object(Dict.t<string>)`
15909+- `Date.t`: `Date(Date.t)`. A JavaScript date.
15910+- `Blob.t`: `Blob(Blob.t)`. A JavaScript blob.
15911+- `File.t`: `File(File.t)`. A JavaScript file.
15912+- `RegExp.t`: `RegExp(RegExp.t)`. A JavaScript regexp instance.
15913+
15914+Again notice that the constructor names can be anything, what matters is what's in the payload.
15915+
15916+> **Under the hood**: Untagged variants uses a combination of JavaScript `typeof` and `instanceof` checks to discern between unboxed constructors at runtime. This means that we could add more things to the list above detailing what can be unboxed, if there are useful enough use cases.
15917+
15918+### Pattern matching on unboxed variants
15919+
15920+Pattern matching works the same on unboxed variants as it does on regular variants. In fact, in the perspective of ReScript's type system there's no difference between untagged and tagged variants. You can do virtually the same things with both. That's the beauty of untagged variants - they're just variants to you as a developer.
15921+
15922+Here's an example of pattern matching on an unboxed nullable value that illustrates the above:
15923+
15924+```rescript
15925+module Null = {
15926+ @unboxed type t<'a> = Present('a) | @as(null) Null
15927+}
15928+
15929+type userAge = {ageNum: Null.t<int>}
15930+
15931+type rec user = {
15932+ name: string,
15933+ age: Null.t<userAge>,
15934+ bestFriend: Null.t<user>,
15935+}
15936+
15937+let getBestFriendsAge = user =>
15938+ switch user.bestFriend {
15939+ | Present({age: Present({ageNum: Present(ageNum)})}) => Some(ageNum)
15940+ | _ => None
15941+ }
15942+```
15943+
15944+No difference to how you'd do with a regular variant. But, the runtime representation is different to a regular variant.
15945+
15946+> Notice how `@as` allows us to say that an untagged variant case should map to a specific underlying _primitive_. `Present` has a type variable, so it can hold any type. And since it's an unboxed type, only the payloads `'a` or `null` will be kept at runtime. That's where the magic comes from.
15947+
15948+### Decoding and encoding JSON idiomatically
15949+
15950+With untagged variants, we have everything we need to define a native JSON type:
15951+
15952+```rescript
15953+@unboxed
15954+type rec json =
15955+ | @as(null) Null
15956+ | Boolean(bool)
15957+ | String(string)
15958+ | Number(float)
15959+ | Object(Dict.t<json>)
15960+ | Array(array<json>)
15961+
15962+let myValidJsonValue = Array([String("Hi"), Number(123.)])
15963+```
15964+
15965+Here's an example of how you could write your own JSON decoders easily using the above, leveraging pattern matching:
15966+
15967+```rescript
15968+@unboxed
15969+type rec json =
15970+ | @as(null) Null
15971+ | Boolean(bool)
15972+ | String(string)
15973+ | Number(float)
15974+ | Object(Dict.t<json>)
15975+ | Array(array<json>)
15976+
15977+type rec user = {
15978+ name: string,
15979+ age: int,
15980+ bestFriend: option<user>,
15981+}
15982+
15983+let rec decodeUser = json =>
15984+ switch json {
15985+ | Object(userDict) =>
15986+ switch (
15987+ userDict->Dict.get("name"),
15988+ userDict->Dict.get("age"),
15989+ userDict->Dict.get("bestFriend"),
15990+ ) {
15991+ | (Some(String(name)), Some(Number(age)), Some(maybeBestFriend)) =>
15992+ Some({
15993+ name,
15994+ age: age->Float.toInt,
15995+ bestFriend: maybeBestFriend->decodeUser,
15996+ })
15997+ | _ => None
15998+ }
15999+ | _ => None
16000+ }
16001+
16002+let decodeUsers = json =>
16003+ switch json {
16004+ | Array(array) => array->Array.map(decodeUser)->Array.keepSome
16005+ | _ => []
16006+ }
16007+```
16008+
16009+Encoding that same structure back into JSON is also easy:
16010+
16011+```rescript
16012+let rec userToJson = user => Object(
16013+ Dict.fromArray([
16014+ ("name", String(user.name)),
16015+ ("age", Number(user.age->Int.toFloat)),
16016+ (
16017+ "bestFriend",
16018+ switch user.bestFriend {
16019+ | None => Null
16020+ | Some(friend) => userToJson(friend)
16021+ },
16022+ ),
16023+ ]),
16024+)
16025+
16026+let usersToJson = users => Array(users->Array.map(userToJson))
16027+```
16028+
16029+This can be extrapolated to many more cases.
16030+
16031+### Advanced: Catch-all Constructors
16032+
16033+With untagged variants comes a rather interesting capability - catch-all cases are now possible to encode directly into a variant.
16034+
16035+Let's look at how it works. Imagine you're using a third party API that returns a list of available animals. You could of course model it as a regular `string`, but given that variants can be used as "typed strings", using a variant would give you much more benefit:
16036+
16037+<CodeTab labels={["ReScript", "JS Output"]}>
16038+```rescript
16039+type animal = Dog | Cat | Bird
16040+
16041+type apiResponse = {
16042+animal: animal
16043+}
16044+
16045+let greetAnimal = (animal: animal) =>
16046+switch animal {
16047+| Dog => "Wof"
16048+| Cat => "Meow"
16049+| Bird => "Kashiiin"
16050+}
16051+
16052+````
16053+```javascript
16054+````
16055+
16056+</CodeTab>
16057+
16058+This is all fine and good as long as the API returns `"Dog"`, `"Cat"` or `"Bird"` for `animal`.
16059+However, what if the API changes before you have a chance to deploy new code, and can now return `"Turtle"` as well? Your code would break down because the variant `animal` doesn't cover `"Turtle"`.
16060+
16061+So, we'll need to go back to `string`, loosing all of the goodies of using a variant, and then do manual conversion into the `animal` variant from `string`, right?
16062+Well, this used to be the case before, but not anymore! We can leverage untagged variants to bake in handling of unknown values into the variant itself.
16063+
16064+Let's update our type definition first:
16065+
16066+```rescript
16067+@unboxed
16068+type animal = Dog | Cat | Bird | UnknownAnimal(string)
16069+```
16070+
16071+Notice we've added `@unboxed` and the constructor `UnknownAnimal(string)`. Remember how untagged variants work? You remove the constructors and just leave the payloads. This means that the variant above at runtime translates to this (made up) JavaScript type:
16072+
16073+```
16074+type animal = "Dog" | "Cat" | "Bird" | string
16075+```
16076+
16077+So, any string not mapping directly to one of the payloadless constructors will now map to the general `string` case.
16078+
16079+As soon as we've added this, the compiler complains that we now need to handle this additional case in our pattern match as well. Let's fix that:
16080+
16081+<CodeTab labels={["ReScript", "JS Output"]}>
16082+```rescript
16083+@unboxed
16084+type animal = Dog | Cat | Bird | UnknownAnimal(string)
16085+
16086+type apiResponse = {
16087+animal: animal
16088+}
16089+
16090+let greetAnimal = (animal: animal) =>
16091+switch animal {
16092+| Dog => "Wof"
16093+| Cat => "Meow"
16094+| Bird => "Kashiiin"
16095+| UnknownAnimal(otherAnimal) =>
16096+`I don't know how to greet animal ${otherAnimal}`
16097+}
16098+
16099+````
16100+```javascript
16101+function greetAnimal(animal) {
16102+ if (!(animal === "Cat" || animal === "Dog" || animal === "Bird")) {
16103+ return "I don't know how to greet animal " + animal;
16104+ }
16105+ switch (animal) {
16106+ case "Dog" :
16107+ return "Wof";
16108+ case "Cat" :
16109+ return "Meow";
16110+ case "Bird" :
16111+ return "Kashiiin";
16112+
16113+ }
16114+}
16115+````
16116+
16117+</CodeTab>
16118+
16119+There! Now the external API can change as much as it wants, we'll be forced to write all code that interfaces with `animal` in a safe way that handles all possible cases. All of this baked into the variant definition itself, so no need for labor intensive manual conversion.
16120+
16121+This is useful in any scenario when you use something enum-style that's external and might change. Additionally, it's also useful when something external has a large number of possible values that are known, but where you only care about a subset of them. With a catch-all case you don't need to bind to all of them just because they can happen, you can safely just bind to the ones you care about and let the catch-all case handle the rest.
16122+
16123+## Coercion
16124+
16125+In certain situations, variants can be coerced to other variants, or to and from primitives. Coercion is always zero cost.
16126+
16127+### Coercing Variants to Other Variants
16128+
16129+You can coerce a variant to another variant if they're identical in runtime representation, and additionally if the variant you're coercing can be represented as the variant you're coercing to.
16130+
16131+Here's an example using [variant type spreads](#variant-type-spreads):
16132+
16133+```rescript
16134+type a = One | Two | Three
16135+type b = | ...a | Four | Five
16136+
16137+let one: a = One
16138+let four: b = Four
16139+
16140+// This works because type `b` can always represent type `a` since all of type `a`'s constructors are spread into type `b`
16141+let oneAsTypeB = (one :> b)
16142+```
16143+
16144+### Coercing Variants to Primitives
16145+
16146+Variants that are guaranteed to always be represented by a single primitive at runtime can be coerced to that primitive.
16147+
16148+It works with strings, the default runtime representation of payloadless constructors:
16149+
16150+```rescript
16151+// Constructors without payloads are represented as `string` by default
16152+type a = One | Two | Three
16153+
16154+let one: a = One
16155+
16156+// All constructors are strings at runtime, so you can safely coerce it to a string
16157+let oneAsString = (one :> string)
16158+```
16159+
16160+If you were to configure all of your constructors to be represented as `int` or `float`, you could coerce to those too:
16161+
16162+```rescript
16163+type asInt = | @as(1) One | @as(2) Two | @as(3) Three
16164+
16165+let oneInt: asInt = One
16166+let toInt = (oneInt :> int)
16167+```
16168+
16169+### Advanced: Coercing `string` to Variant
16170+
16171+In certain situations it's possible to coerce a `string` to a variant. This is an advanced technique that you're unlikely to need much, but when you do it's really useful.
16172+
16173+You can coerce a `string` to a variant when:
16174+
16175+- Your variant is `@unboxed`
16176+- Your variant has a "catch-all" `string` case
16177+
16178+Let's look at an example:
16179+
16180+```rescript
16181+@unboxed
16182+type myEnum = One | Two | Other(string)
16183+
16184+// Other("Other thing")
16185+let asMyEnum = ("Other thing" :> myEnum)
16186+
16187+// One
16188+let asMyEnum = ("One" :> myEnum)
16189+```
16190+
16191+This works because the variant is unboxed **and** has a catch-all case. So, if you throw a string at this variant that's not representable by the payloadless constructors, like `"One"` or `"Two"`, it'll _always_ end up in `Other(string)`, since that case can represent any `string`.
16192+
16193+## Tips & Tricks
16194+
16195+**Be careful** not to confuse a constructor carrying 2 arguments with a constructor carrying a single tuple argument:
16196+
16197+<CodeTab labels={["ReScript", "JS Output"]}>
16198+
16199+```res
16200+type accountWithTwoArguments =
16201+ | Facebook(string, int) // 2 arguments
16202+type accountWithTupleArgument =
16203+ | Instagram((string, int)) // 1 argument - happens to be a 2-tuple
16204+```
16205+
16206+```js
16207+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
16208+```
16209+
16210+</CodeTab>
16211+
16212+### Variants Must Have Constructors
16213+
16214+If you come from an untyped language, you might be tempted to try `type myType = int | string`. This isn't possible in ReScript; you'd have to give each branch a constructor: `type myType = Int(int) | String(string)`. The former looks nice, but causes lots of trouble down the line.
16215+
16216+### Interop with JavaScript
16217+
16218+_This section assumes knowledge about our JavaScript interop. Skip this if you haven't felt the itch to use variants for wrapping JS functions yet_.
16219+
16220+Quite a few JS libraries use functions that can accept many types of arguments. In these cases, it's very tempting to model them as variants. For example, suppose there's a `myLibrary.draw` JS function that takes in either a `number` or a `string`. You might be tempted to bind it like so:
16221+
16222+<CodeTab labels={["ReScript", "JS Output"]}>
16223+
16224+```res
16225+// reserved for internal usage
16226+@module("myLibrary") external draw : 'a => unit = "draw"
16227+
16228+type animal =
16229+ | MyFloat(float)
16230+ | MyString(string)
16231+
16232+let betterDraw = (animal) =>
16233+ switch animal {
16234+ | MyFloat(f) => draw(f)
16235+ | MyString(s) => draw(s)
16236+ }
16237+
16238+betterDraw(MyFloat(1.5))
16239+```
16240+
16241+```js
16242+import * as MyLibrary from "myLibrary";
16243+
16244+function betterDraw(animal) {
16245+ MyLibrary.draw(animal._0);
16246+}
16247+
16248+betterDraw({
16249+ TAG: "MyFloat",
16250+ _0: 1.5,
16251+});
16252+
16253+export { betterDraw };
16254+```
16255+
16256+</CodeTab>
16257+
16258+**Try not to do that**, as this generates extra noisy output. Instead, use the `@unboxed` attribute to guide ReScript to generate more efficient code:
16259+
16260+<CodeTab labels={["ReScript", "JS Output"]}>
16261+
16262+```res
16263+// reserved for internal usage
16264+@module("myLibrary") external draw : 'a => unit = "draw"
16265+
16266+@unboxed
16267+type animal =
16268+ | MyFloat(float)
16269+ | MyString(string)
16270+
16271+let betterDraw = (animal) =>
16272+ switch animal {
16273+ | MyFloat(f) => draw(f)
16274+ | MyString(s) => draw(s)
16275+ }
16276+
16277+betterDraw(MyFloat(1.5))
16278+```
16279+
16280+```js
16281+import * as MyLibrary from "myLibrary";
16282+
16283+function betterDraw(animal) {
16284+ MyLibrary.draw(animal);
16285+}
16286+
16287+MyLibrary.draw(1.5);
16288+
16289+export { betterDraw };
16290+```
16291+
16292+</CodeTab>
16293+
16294+Alternatively, define two `external`s that both compile to the same JS call:
16295+
16296+<CodeTab labels={["ReScript", "JS Output"]}>
16297+
16298+```res
16299+@module("myLibrary") external drawFloat: float => unit = "draw"
16300+@module("myLibrary") external drawString: string => unit = "draw"
16301+```
16302+
16303+```js
16304+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
16305+```
16306+
16307+</CodeTab>
16308+
16309+ReScript also provides [a few other ways](./bind-to-js-function.mdx#modeling-polymorphic-function) to do this.
16310+
16311+### Variant Types Are Found By Field Name
16312+
16313+Please refer to this [record section](./record.mdx#tips--tricks). Variants are the same: a function can't accept an arbitrary constructor shared by two different variants. Again, such feature exists; it's called a polymorphic variant. We'll talk about this in the future =).
16314+
16315+## Design Decisions
16316+
16317+Variants, in their many forms (polymorphic variant, open variant, GADT, etc.), are likely _the_ feature of a type system such as ReScript's. The aforementioned `option` variant, for example, obliterates the need for nullable types, a major source of bugs in other languages. Philosophically speaking, a problem is composed of many possible branches/conditions. Mishandling these conditions is the majority of what we call bugs. **A type system doesn't magically eliminate bugs; it points out the unhandled conditions and asks you to cover them**\*. The ability to model "this or that" correctly is crucial.
16318+
16319+For example, some folks wonder how the type system can safely eliminate badly formatted JSON data from propagating into their program. They don't, not by themselves! But if the parser returns the `option` type `None | Some(actualData)`, then you'd have to handle the `None` case explicitly in later call sites. That's all there is.
16320+
16321+Performance-wise, a variant can potentially tremendously speed up your program's logic. Here's a piece of JavaScript:
16322+
16323+```js
16324+let data = 'dog'
16325+function logData(data) {
16326+ if (data === 'dog') {
16327+ ...
16328+ } else if (data === 'cat') {
16329+ ...
16330+ } else if (data === 'bird') {
16331+ ...
16332+ }
16333+}
16334+logData(data)
16335+```
16336+
16337+There's a linear amount of branch checking here (`O(n)`). Compare this to using a ReScript variant:
16338+
16339+<CodeTab labels={["ReScript", "JS Output"]}>
16340+
16341+```res
16342+type animal = Dog | Cat | Bird
16343+let data = Dog
16344+let logData = data => {
16345+ switch data {
16346+ | Dog => Console.log("Wof")
16347+ | Cat => Console.log("Meow")
16348+ | Bird => Console.log("Kashiiin")
16349+ }
16350+}
16351+logData(data)
16352+
16353+```
16354+
16355+```js
16356+function logData(data) {
16357+ switch (data) {
16358+ case "Dog":
16359+ console.log("Wof");
16360+ return;
16361+ case "Cat":
16362+ console.log("Meow");
16363+ return;
16364+ case "Bird":
16365+ console.log("Kashiiin");
16366+ return;
16367+ }
16368+}
16369+
16370+logData("Dog");
16371+
16372+let data = "Dog";
16373+
16374+export { data, logData };
16375+```
16376+
16377+</CodeTab>
16378+
16379+The compiler sees the variant, then
16380+
16381+1. conceptually turns them into `type animal = "Dog" | "Cat" | "Bird"`
16382+2. compiles `switch` to a constant-time jump table (`O(1)`).
16383+
16384+---
16385+title: "Warning Numbers"
16386+description: "Available compiler warning numbers in ReScript"
16387+canonical: "/docs/manual/warning-numbers"
16388+section: "Build System"
16389+order: 8
16390+---
16391+
16392+# Warning Numbers
16393+
16394+You can configure which warnings the ReScript compiler generates
16395+[in the build configuration](./build-configuration.mdx#warnings) or
16396+using the [`@warning()`](../../syntax-lookup/decorator_expression_warning.mdx) or the [`@@warning()`](../../syntax-lookup/decorator_module_warning.mdx) decorator.
16397+
16398+<WarningTable />
16399+
1@@ -0,0 +1,5589 @@
2+# Introduction
3+
4+## Stdlib
5+
6+[Stdlib](/docs/manual/api/stdlib) is ReScript's new builtin standard library.
7+It will cover just about you need for day-to-day programming in ReScript and covers most of the built in JavaScript API.
8+
9+## Additional Libraries
10+
11+ReScript ships with these two additional modules in its standard library:
12+
13+- [Belt](/docs/manual/api/belt): immutable collections and extra helpers not available in JavaScript / [Stdlib](/docs/manual/api/stdlib).
14+- [Dom](/docs/manual/api/stdlibdom): Dom related types and modules. Contains our standardized types used by various userland DOM bindings.
15+# Array and List
16+
17+## Array
18+
19+Arrays are the main ordered data structure in ReScript. They can be randomly accessed, dynamically resized, and updated.
20+
21+
22+
23+ReScript arrays' items must have the same type, i.e. homogeneous.
24+
25+### Usage
26+
27+#### Access
28+
29+Accessing items in an array will return an `option` and can be done like so:
30+
31+
32+
33+#### Update
34+
35+Items in an array can be updated by assigning a value to an index or using a function:
36+
37+
38+
39+### Array spreads
40+
41+**Since 11.1**
42+
43+You can spread arrays of the same type into new arrays:
44+
45+
46+
47+## List
48+
49+ReScript provides a singly linked list too. Lists are:
50+
51+- immutable
52+- fast at prepending items
53+- fast at getting the head
54+- slow at everything else
55+
56+
57+
58+Like arrays, lists' items need to be of the same type.
59+
60+### Usage
61+
62+You'd use list for its resizability, its fast prepend (adding at the head), and its fast split, all of which are immutable and relatively efficient.
63+
64+Do **not** use list if you need to randomly access an item or insert at non-head position. Your code would end up obtuse and/or slow.
65+
66+For accessing deeper, see [destructuring](./pattern-matching-destructuring.mdx).
67+
68+#### Immutable Prepend
69+
70+Use the spread syntax:
71+
72+
73+
74+`myList` didn't mutate. `anotherList` is now `list{0, 1, 2, 3}`. This is efficient (constant time, not linear). `anotherList`'s last 3 elements are shared with `myList`!
75+
76+**Note that `list{a, ...b, ...c}` was a syntax error** before compiler v10.1. In general, the pattern should be used with care as its performance and allocation overhead are linear (`O(n)`).
77+
78+#### Access
79+
80+`switch` (described in the [pattern matching section](./pattern-matching-destructuring.mdx)) is usually used to access list items:
81+
82+
83+{/* This prelude is used in many different followup examples, so we use it to shorten the noise of the example code. */}
84+
85+<div className="hidden">
86+
87+
88+
89+</div>
90+
91+{/* See https://github.com/cristianoc/rescript-compiler-experiments/pull/1#issuecomment-1131182023 for all async/await use-case examples */}
92+
93+# Async / Await
94+
95+ReScript comes with `async` / `await` support to make asynchronous, `Promise` based code easier to read and write. This feature is very similar to its JS equivalent, so if you are already familiar with JS' `async` / `await`, you will feel right at home.
96+
97+## How it looks
98+
99+Let's start with a quick example to show-case the syntax:
100+
101+
102+
103+As we can see above, an `async` function is defined via the `async` keyword right before the function's parameter list. In the function body, we are now able to use the `await` keyword to explicitly wait for a `Promise` value and assign its content to a let binding `email`.
104+
105+You will probably notice that this looks very similar to `async` / `await` in JS, but there are still a few details that are specific to ReScript. The next few sections will go through all the details that are specific to the ReScript type system.
106+
107+## Basics
108+
109+- You may only use `await` in `async` function bodies
110+- `await` may only be called on a `promise` value
111+- `await` calls are expressions, therefore they can be used in pattern matching (`switch`)
112+- A function returning a `promise<'a>` is equivalent to an `async` function returning a value `'a` (important for writing signature files and bindings)
113+- `promise` values and types returned from an `async` function don't auto-collapse into a flat promise. See the details below.
114+
115+## Types and `async` functions
116+
117+### `async` function type signatures
118+
119+Function type signatures (i.e defined in signature files) don't require any special keywords for `async` usage. Whenever you want to type an `async` function, use a `promise` return type.
120+
121+
122+
123+The same logic applies to type definitions in `.res` files:
124+
125+
126+
127+**BUT:** When typing `async` functions in your implementation files, you need to omit the `promise<'a>` type:
128+
129+
130+
131+For completeness reasons, let's expand the full signature and inline type definitions in one code snippet:
132+
133+
134+
135+**Note:** In a practical scenario you'd either use a type signature, or inline types, not both at the same time. In case you are interested in the design decisions, check out [this discussion](https://github.com/rescript-lang/rescript-compiler/pull/5913#issuecomment-1359003870).
136+
137+### Promises don't auto-collapse in async functions
138+
139+In JS, nested promises (i.e. `promise<promise<'a>>`) will automatically collapse into a flat promise (`promise<'a>`). This is not the case in ReScript. Use the `await` function to manually unwrap any nested promises within an `async` function instead.
140+
141+
142+
143+## Error handling
144+
145+You may use `try / catch` or `switch` to handle exceptions during async execution.
146+
147+
148+
149+Note how we are essentially catching JS errors the same way as described in our [Exception](./exception.mdx#catch-rescript-exceptions-from-js) section.
150+
151+You may unify error and value handling in a single switch as well:
152+
153+
154+
155+**Important:** When using `await` with a `switch`, always make sure to put the actual await call in the `switch` expression, otherwise your `await` error will not be caught.
156+
157+## Piping `await` calls
158+
159+You may want to pipe the result of an `await` call right into another function.
160+This can be done by wrapping your `await` calls in a new `{}` closure.
161+
162+
163+
164+Note how the original closure was removed in the final JS output. No extra allocations!
165+
166+## Pattern matching on `await` calls
167+
168+`await` calls are just another kind of expression, so you can use `switch` pattern matching for more complex logic.
169+
170+
171+
172+## `await` multiple promises
173+
174+We can utilize the `Promise` module to handle multiple promises. E.g. let's use `Promise.all` to wait for multiple promises before continuing the program:
175+
176+
177+
178+## JS Interop with `async` functions
179+
180+`async` / `await` practically works with any function that returns a `promise<'a>` value. Map your `promise` returning function via an `external`, and use it in an `async` function as usual.
181+
182+Here's a full example of using the MDN `fetch` API, using `async` / `await` to simulate a login:
183+
184+
185+# Attribute (Decorator)
186+
187+Like many other languages, ReScript allows annotating a piece of code to express extra functionality. Here's an example:
188+
189+
190+
191+The `@inline` annotation tells `mode`'s value to be inlined into its usage sites (see output). We call such annotation "attribute" (or "decorator" in JavaScript).
192+
193+An attribute starts with `@` and goes before the item it annotates. In the above example, it's hooked onto the let binding.
194+
195+## Usage
196+
197+> **Note:** In previous versions (< 8.3) all our interop related attributes started with a `bs.` prefix (`bs.module`, `bs.val`). Our formatter will automatically drop them in newer ReScript versions.
198+
199+You can put an attribute almost anywhere. You can even add extra data to them by using them visually like a function call. Here are a few famous attributes (explained in other sections):
200+
201+
202+
203+1. `@@warning("-27")` is a standalone attribute that annotates the entire file. Those attributes start with `@@`. Here, it carries the data `"-27"`. You can find a full list of all available warnings [here](./warning-numbers.mdx).
204+2. `@unboxed` annotates the type definition.
205+3. `@val` annotates the `external` statement.
206+4. `@as("aria-label")` annotates the `ariaLabel` record field.
207+5. `@deprecated` annotates the `customDouble` expression. This shows a warning while compiling telling consumers to not rely on this method long-term.
208+6. `@deprecated("Use SomeOther.customTriple instead")` annotates the `customTriple` expression with a string to describe the reason for deprecation.
209+
210+For a list of all decorators and their usage, please refer to the [Syntax Lookup](../../syntax-lookup/) page.
211+
212+## Extension Point
213+
214+There's a second category of attributes, called "extension points" (a remnant term of our early systems):
215+
216+
217+
218+Extension points are attributes that don't _annotate_ an item; they _are_ the item. Usually they serve as placeholders for the compiler to implicitly substitute them with another item.
219+
220+Extension points start with `%`. A standalone extension point (akin to a standalone regular attribute) starts with `%%`.
221+
222+For a list of all extension points and their usage, please refer to the [Syntax Lookup](../../syntax-lookup/) page.
223+# Bind to Global JS Values
224+
225+**First**, make sure the value you'd like to model doesn't already exist in our [provided API](/docs/manual/api/stdlib).
226+
227+Some JS values, like `setTimeout`, live in the global scope. You can bind to them like so:
228+
229+
230+
231+(We already provide `setTimeout`, `clearTimeout` and others in the [Core API](/docs/manual/api/stdlib) module).
232+
233+This binds to the JavaScript [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrworkerGlobalScope/setTimeout) methods and the corresponding `clearTimeout`. The `external`'s type annotation specifies that `setTimeout`:
234+
235+- Takes a function that accepts `unit` and returns `unit` (which on the JS side turns into a function that accepts nothing and returns nothing aka `undefined`),
236+- and an integer that specifies the duration before calling said function,
237+- returns a number that is the timeout's ID. This number might be big, so we're modeling it as a float rather than the 32-bit int.
238+
239+### Tips & Tricks
240+
241+**The above isn't ideal**. See how `setTimeout` returns a `float` and `clearTimeout` accepts one. There's no guarantee that you're passing the float created by `setTimeout` into `clearTimeout`! For all we know, someone might pass it `Math.random()` into the latter.
242+
243+We're in a language with a great type system now! Let's leverage a popular feature to solve this problem: abstract types.
244+
245+
246+
247+Clearly, `timerId` is a type that can only be created by `setTimeout`! Now we've guaranteed that `clearTimeout` _will_ be passed a valid ID. Whether it's a number under the hood is now a mere implementation detail.
248+
249+Since `external`s are inlined, we end up with JS output as readable as hand-written JS.
250+
251+## Global Modules
252+
253+If you want to bind to a value inside a global module, e.g. `Math.random`, attach a `scope` to your `val` external:
254+
255+
256+
257+you can bind to an arbitrarily deep object by passing a tuple to `scope`:
258+
259+
260+
261+This binds to `window.location.ancestorOrigins.length`.
262+
263+## Special Global Values
264+
265+Global values like `__filename` and `__DEV__` don't always exist; you can't even model them as an `option`, since the mere act of referring to them in ReScript (then compiled into JS) would trigger the usual `Uncaught ReferenceError: __filename is not defined` error in e.g. the browser environment.
266+
267+For these troublesome global values, ReScript provides a special approach: `%external(a_single_identifier)`.
268+
269+
270+
271+That first line's `typeof` check won't trigger a JS ReferenceError.
272+
273+Another example:
274+
275+
276+
277+{/* TODO: revamp this page. Not good. Tell to use globalThis["foo"], and look in our stdlib */}
278+# Function
279+
280+Binding a JS function is like binding any other value:
281+
282+
283+
284+We also expose a few special features, described below.
285+
286+## Labeled Arguments
287+
288+ReScript has [function](./function.mdx) signature. These work on an `external` too! You'd use them to _fix_ a JS function's unclear usage. Assuming we're modeling this:
289+
290+
291+
292+It'd be nice if on ReScript's side, we can bind & call `draw` while labeling things a bit:
293+
294+
295+
296+We've compiled to the same function, but now the usage is much clearer on the ReScript side thanks to labels!
297+
298+Note that you can freely reorder the labels on the ReScript side; they'll always correctly appear in their declaration order in the JavaScript output:
299+
300+
301+
302+## Object Method
303+
304+Functions attached to JS objects (other than JS modules) require a special way of binding to them, using `send`:
305+
306+
307+
308+In a `send`, the object is always the first argument. Actual arguments of the method follow (this is a bit what modern OOP objects are really).
309+
310+### Chaining
311+
312+Ever used `foo().bar().baz()` chaining ("fluent api") in JS OOP? We can model that in ReScript too, through the [pipe operator](./pipe.mdx).
313+
314+### Nested function call
315+
316+`@send` can also accept a `@scope(("itemOne","itemTwo"))` to access a function on a nested property.
317+
318+
319+
320+## Variadic Function Arguments
321+
322+You might have JS functions that take an arbitrary amount of arguments. ReScript supports modeling those, under the condition that the arbitrary arguments part is homogenous (aka of the same type). If so, add `variadic` to your `external`.
323+
324+
325+
326+`module` will be explained in [Import from/Export to JS](./import-from-export-to-js.mdx).
327+
328+## Modeling Polymorphic Function
329+
330+Apart from the above special-case, JS functions in general are often arbitrarily overloaded in terms of argument types and number. How would you bind to those?
331+
332+### Trick 1: Multiple `external`s
333+
334+If you can exhaustively enumerate the many forms an overloaded JS function can take, simply bind to each differently:
335+
336+
337+
338+Note how all three externals bind to the same JS function, `draw`.
339+
340+### Trick 2: Polymorphic Variant + `unwrap`
341+
342+If you have the irresistible urge of saying "if only this JS function argument was a variant instead of informally being either `string` or `int`", then good news: we do provide such `external` features through annotating a parameter as a polymorphic variant! Assuming you have the following JS function you'd like to bind to:
343+
344+
345+
346+Here, `padding` is really conceptually a variant. Let's model it as such.
347+
348+
349+
350+Obviously, the JS side couldn't have an argument that's a polymorphic variant! But here, we're just piggy backing on poly variants' type checking and syntax. The secret is the `@unwrap` annotation on the type. It strips the variant constructors and compile to just the payload's value. See the output.
351+
352+## Constrain Arguments Better
353+
354+Consider the Node `fs.readFileSync`'s second argument. It can take a string, but really only a defined set: `"ascii"`, `"utf8"`, etc. You can still bind it as a string, but we can use poly variants + `string` to ensure that our usage's more correct:
355+
356+
357+
358+- Attaching `@string` to the whole poly variant type makes its constructor compile to a string of the same name.
359+- Attaching a `@as("bla")` to a constructor lets you customize the final string.
360+
361+And now, passing something like `"myOwnUnicode"` or other variant constructor names to `readFileSync` would correctly error.
362+
363+Aside from string, you can also compile an argument to an int, using `int` instead of `string` in a similar way:
364+
365+
366+
367+`onClosed` compiles to `0`, `onOpen` to `20` and `inBinary` to **`21`**.
368+
369+## Unknown for type safety
370+
371+It is best practice to inspect data received from untrusted external functions to ensure it contains what you expect. This helps avoid run-time crashes and unexpected behavior. If you're certain about what an external function returns, simply assert the return value as `string` or `array<int>` or whatever you want it to be. Otherwise use `unknown`. The ReScript type system will prevent you from using an `unknown` until you first inspect it and "convert" it using JSON parsing utilities or similar tools.
372+
373+Consider the example below of two external functions that access the value of a property on a JavaScript object. `getPropertyUnsafe` returns an `'a`, which means "anything you want it to be." ReScript allows you to use this value as a `string` or `array` or any other type. Quite convenient! But if the property is missing or contains something unexpected, your code might break. You can make the binding more safe by changing `'a` to `string` or `option<'a>`, but this doesn't completely eliminate the problem.
374+
375+The `getPropertySafe` function returns an `unknown`, which could be `null` or a `string` or anything else. But ReScript prevents you from using this value inappropriately until it has been safely parsed.
376+
377+
378+
379+## Special-case: Event Listeners
380+
381+One last trick with polymorphic variants:
382+
383+
384+
385+{/* TODO: GADT phantom type */}
386+
387+## Fixed Arguments
388+
389+Sometimes it's convenient to bind to a function using an `external`, while passing predetermined argument values to the JS function:
390+
391+
392+
393+The `@as("exit")` and the placeholder `_` argument together indicates that you want the first argument to compile to the string `"exit"`. You can also use any JSON literal with `as`: ``@as(json`true`)``, ``@as(json`{"name": "John"}`)``, etc.
394+
395+## Ignore arguments
396+
397+You can also explicitly "hide" `external` function parameters in the JS output, which may be useful if you want to add type constraints to other parameters without impacting the JS side:
398+
399+
400+
401+**Note:** It's a pretty niche feature, mostly used to map to polymorphic JS APIs.
402+
403+## Modeling `this`-based Callbacks
404+
405+Many JS libraries have callbacks which rely on this (the source), for example:
406+
407+
408+
409+Here, `this` would point to `x` (actually, it depends on how `onload` is called, but we digress). It's not correct to declare `x.onload` of type `(. unit) -> unit`. Instead, we introduced a special attribute, `this`, which allows us to type `x` as so:
410+
411+
412+
413+`@this` reserves the first parameter for the `this` value, and for arity of 0, there is no need for a redundant `unit` type.
414+
415+## Function Nullable Return Value Wrapping
416+
417+For JS functions that return a value that can also be `undefined` or `null`, we provide `@return(...)`. To automatically convert that value to an `option` type (recall that ReScript `option` type's `None` value only compiles to `undefined` and not `null`).
418+
419+
420+
421+`return(nullable)` attribute will automatically convert `null` and `undefined` to `option` type.
422+
423+Currently 4 directives are supported: `null_to_opt`, `undefined_to_opt`, `nullable` and `identity`.
424+
425+{/* When the return type is unit: the compiler will append its return value with an OCaml unit literal to make sure it does return unit. Its main purpose is to make the user consume FFI in idiomatic OCaml code, the cost is very very small and the compiler will do smart optimizations to remove it when the returned value is not used (mostly likely). */}
426+
427+`identity` will make sure that compiler will do nothing about the returned value. It is rarely used, but introduced here for debugging purpose.
428+
429+## Tagged template functions
430+
431+**Since 11.1**
432+
433+**Experimental** You can easily bind to [JS tagged template functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates).
434+Tag functions in JS expect as input an array of strings and variadic parameters for the arguments of the interpolation.
435+To bind to those functions in ReScript, the binding signature must have two arrays as arguments,
436+the first one being an array of strings and the second can be an array of anything.
437+You add the `@taggedTemplate` annotation and you're good to go!
438+
439+
440+
441+Notice that it gets compiled to tagged template literals in JS, which allows
442+to use JS tools that only work on the literals and not by calling directly the tag function.
443+
444+There are plenty of useful JS tools you can bind to, like [`gql`](https://github.com/apollographql/graphql-tag),
445+[`sql`](https://github.com/porsager/postgres), [`css`](https://github.com/mayank99/ecsstatic) and a lot others!
446+# Bind to JS Object
447+
448+JavaScript objects are a combination of several use-cases:
449+
450+- As a "record" or "struct" in other languages (like ReScript and C).
451+- As a hash map.
452+- As a class.
453+- As a module to import/export.
454+
455+ReScript cleanly separates the binding methods for JS object based on these 4 use-cases. This page documents the first three. Binding to JS module objects is described in the [Import from/Export to JS](./import-from-export-to-js.mdx) section.
456+
457+{/* TODO: mention scope here too? */}
458+
459+## Bind to Record-like JS Objects
460+
461+### Bind Using ReScript Record
462+
463+If your JavaScript object has fixed fields, then it's conceptually like a ReScript record. Since a ReScript record compiles to a clean JavaScript object, you can definitely type a JS object as a ReScript record!
464+
465+
466+
467+External is documented [here](./external.mdx). `@module` is documented [here](./import-from-export-to-js.mdx).
468+
469+If you want or need to use different field names on the ReScript and the JavaScript side, you can use the `@as` decorator:
470+
471+
472+
473+This is useful to map to JavaScript attribute names that cannot be expressed in ReScript (such as keywords).
474+
475+It is also possible to map a ReScript record to a JavaScript array by passing indices to the `@as` decorator:
476+
477+
478+
479+### Bind Using ReScript Object
480+
481+Alternatively, you can use [ReScript object](./object.mdx) to model a JS object too:
482+
483+
484+
485+### Bind Using Special Getter and Setter Attributes
486+
487+Alternatively, you can use `get` and `set` to bind to individual fields of a JS object:
488+
489+
490+
491+You can also use `get_index` and `set_index` to access a dynamic property or an index:
492+
493+
494+
495+## Bind to Hash Map-like JS Object
496+
497+If your JavaScript object:
498+
499+- might or might not add/remove keys
500+- contains only values that are of the same type
501+
502+Then it's not really an object, it's a hash map. Use [Dict](/docs/manual/api/stdlib/dict), which contains operations like `get`, `set`, etc. and cleanly compiles to a JavaScript object still.
503+
504+## Bind to a JS Object That's a Class
505+
506+Use `new` to emulate e.g. `new Date()`:
507+
508+
509+
510+You can chain `new` and `module` if the JS module you're importing is itself a class:
511+
512+
513+<Suspense>
514+ <Docson tag="master" />
515+</Suspense>
516+# Configuration
517+
518+`rescript.json` is the single, mandatory build meta file needed for `rescript`.
519+
520+**The complete configuration schema is [here](./build-configuration-schema.mdx)**. We'll _non-exhaustively_ highlight the important parts in prose below.
521+
522+## name, namespace
523+
524+`name` is the name of the library, used as its "namespace". You can activate namespacing through `"namespace": true` in your `rescript.json`. Namespacing is almost **mandatory**; we haven't turned it on by default yet to preserve backward-compatibility.
525+
526+**Explanation**: by default, your files, once used as a third-party dependency, are available globally to the consumer. E.g. if you have a `Util.res` and the consumer also has a file of the same name, they will clash. Turning on `namespace` avoids this by wrapping all your own project's files into an extra module layer; instead of a global `Util` module, the consumer will see you as `MyProject.Util`. **The namespacing affects your consumers, not yourself**.
527+
528+Aka, in ReScript, "namespace" is just a fancy term for an auto-generated module that wraps all your project's files (efficiently and correctly, of course!) for third-party consumption.
529+
530+We don't do folder-level namespacing for your own project; all your own file names must be unique. This is a constraint that enables several features such as fast search and easier project reorganization.
531+
532+**Note**: the `rescript.json` `name` should be the same as the `package.json` `name`, to avoid confusing corner-cases. However, this means that you can't use a camelCased names such as `MyProject`, since `package.json` and npm forbid you to do so (some file systems are case-insensitive). To have the namespace/module as `MyProject`, write `"name": "my-project"`. ReScript will turn that into the camelCased name correctly.
533+
534+**Note on custom namespacing**: if for some reason, you need a namespace that is different from what your `name` will produce, you can directly send a string to the `namespace` option. For example, if your package is a binding named `bs-some-thing`, you can use `"namespace": "some-thing"` to get `SomeThing` namespace instead of `BsSomeThing`.
535+
536+## sources
537+
538+Your source files need to be specified explicitly (we don't want to accidentally drill down into some unrelated directories). Examples:
539+
540+
541+
542+
543+
544+
545+
546+You can mark your directories as dev-only (for e.g. tests). These won't be built and exposed to third-parties, or even to other "dev" directories in the same project:
547+
548+
549+
550+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.
551+Here, the file `src/MyMainModule.res` is exposed to outside consumers, while all other files are private.
552+
553+
554+
555+## dependencies, dev-dependencies
556+
557+List of ReScript dependencies. Just like `package.json`'s dependencies, they'll be searched in `node_modules`.
558+
559+Note that only sources marked with `"type":"dev"` will be able to resolve modules from `dev-dependencies`.
560+
561+> The legacy keys `bs-dependencies` and `bs-dev-dependencies` are still accepted but deprecated.
562+
563+## js-post-build
564+
565+Hook that's invoked every time a file is recompiled. Good for JS build system interop, but please use it **sparingly**. Calling your custom command for every recompiled file slows down your build and worsens the building experience for even third-party users of your lib.
566+
567+Example:
568+
569+
570+
571+Note that the path resolution for the command (`node` in this case) is done so:
572+
573+- `/myCommand` is resolved into `/myCommand`
574+- `package/myCommand` is resolved into `node_modules/package/myCommand`
575+- `./myCommand` is resolved into `myProjectRoot/myCommand`
576+- `myCommand` is just called as `myCommand`, aka a globally available executable. But note that ReScript doesn't read into your shell's environment, so if you put e.g. `node`, it won't find it unless you specify an absolute path. Alternatively, add `#!/usr/local/bin/node` to the top of your script to directly call it without prepending `node`.
577+
578+The command itself is called from inside `lib/bs`.
579+
580+## jsx
581+
582+Controls how the compiler emits JSX and which runtime (if any) it delegates to. A minimal configuration looks like this:
583+
584+
585+
586+- `version`: JSX transform version. `4` enables the React 17+ transform and is the current and only supported option in v12.
587+- `module`: Override the target module that receives JSX calls. Useful for [generic JSX transforms](./jsx.mdx#generic-jsx-transform-jsx-beyond-react-experimental); omit it when using the built-in React runtime.
588+- `preserve`: When `true`, the compiler re-emits JSX syntax in the generated JavaScript so bundlers or other tooling can take over the transform later. The regenerated JSX might differ slightly from the original source but stays semantically equivalent. See [Preserve mode](./jsx.mdx#preserve-mode) for details.
589+
590+All fields are optional; unspecified fields fall back to the defaults mentioned above. Combine them as needed for your project's JSX runtime.
591+
592+## package-specs
593+
594+Output to either CommonJS (the default) or JavaScript module. Example:
595+
596+
597+
598+- `"module": "commonjs"` generates output as CommonJS format.
599+- `"module": "esmodule"` generates output as JavaScript module format. Will be default value in next major.
600+- `"in-source": true` generates output alongside source files. If you omit it, it'll generate the artifacts into `lib/js`. The output directory is not configurable otherwise.
601+
602+This configuration only applies to you, when you develop the project. When the project is used as a third-party library, the consumer's own `rescript.json` `package-specs` overrides the configuration here, logically.
603+
604+## suffix
605+
606+**Since 11.0**: The suffix can be freely chosen. However, we still suggest you stick to the convention and use
607+
608+one of the following:
609+
610+- `".js`
611+- `".mjs"`
612+- `".cjs"`
613+- `".res.js"`
614+- `".res.mjs"`
615+- `".res.cjs"`
616+
617+### Design Decisions
618+
619+Generating JS files with the `.res.js` suffix means that, on the JS side, you can do `const myReScriptFile = require('./TheFile.res.js')`. The benefits:
620+
621+- It's immediately clear that we're dealing with a generated JS file here.
622+- It avoids clashes with a potential `TheFile.js` file in the same folder.
623+- 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**.
624+
625+## warnings
626+
627+Selectively turn on/off certain warnings and/or turn them into hard errors. Example:
628+
629+
630+
631+Turn off warning `44` and `102` (polymorphic comparison). Turn warning `5` (partial application whose result has function type and is ignored) into a hard error.
632+
633+The warning numbers are shown in the build output when they're triggered. See [Warning Numbers](./warning-numbers.mdx) for the complete list.
634+
635+## compiler-flags
636+
637+Extra flags to pass to the compiler. For advanced usages.
638+
639+- `-open ABC` opens the module `ABC` for each file in the project. `ABC` can either be a dependency, namespaced project or local module of the current project.
640+
641+> The legacy key `bsc-flags` is still accepted but deprecated.
642+
643+## gentypeconfig
644+
645+To enable genType, set `"gentypeconfig"` at top level in the project's `rescript.json`.
646+
647+
648+
649+`generatedFileExtension`: File extension used for genType generated files (defaults to `".gen.tsx"`)
650+
651+`module`: Module format used for the generated `*.gen.tsx` files (supports `"esmodule"` and `"commonjs"`)
652+
653+`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`.
654+
655+- `"node"`(default): Drop extensions in import paths.
656+- `"node16"`: Use TS output's extension. This provides compatibility with projects using `"moduleResolution": "node16"` and ES Modules.
657+- `"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`
658+
659+`debug`: Enable debug logs.
660+
661+## Environment Variables
662+
663+We heavily disrecommend the usage of environment variables, but for certain cases, they're justified.
664+
665+### Error Output Coloring: `FORCE_COLOR`
666+
667+This is mostly for other programmatic usage of `rescript` where outputting colors is not desired.
668+
669+When `FORCE_COLOR` is set to `1`: `rescript` produces color.
670+When `FORCE_COLOR` is set to `0`: `rescript` doesn't produce color.
671+When `FORCE_COLOR` is not set: `rescript` might or might not produce color, depending on a smart detection of where it's outputted.
672+
673+> Note that the underlying compiler will always be passed `-color always`. See more details in [this issue](https://github.com/rescript-lang/rescript-compiler/issues/2984#issuecomment-410669163).
674+# Setting up a monorepo with ReScript
675+
676+**Since 12.0**
677+
678+> A monorepo is a single repository containing multiple separate projects, with clear relationships between them.
679+
680+ReScript 12.0 introduces improved support for native monorepos through the new ["Rewatch"](../../blog/reforging-build-system.mdx) build system. This guide walks you through the setup process.
681+
682+**Note:** This feature requires the new build system and is **not compatible** with `rescript-legacy`.
683+
684+## Project Structure
685+
686+A ReScript monorepo requires a `rescript.json` file at the repository root, plus a `rescript.json` file in each sub-project directory.
687+Basically, the monorepo contains a root package that manages all local dependencies. Building the root package will build all its dependencies.
688+
689+**Important:** You also need a node_modules monorepo setup with symlinks. In practice, if you want a ReScript monorepo, you will also need an npm/yarn/pnpm/bun monorepo.
690+
691+A typical structure looks like this:
692+
693+```
694+my-monorepo/
695+├── rescript.json
696+├── package.json
697+├── node_modules/
698+│ ├── package-1/ # symlinked
699+│ ├── package-2/ # symlinked
700+├── packages/
701+│ ├── package-1/
702+│ │ ├── rescript.json
703+│ │ ├── package.json
704+│ │ ├── src/
705+│ ├── package-2/
706+│ │ ├── rescript.json
707+│ │ ├── package.json
708+│ │ ├── src/
709+│ ├── ...
710+```
711+
712+## Root `rescript.json` Configuration
713+
714+The root `rescript.json` manages the monorepo by listing its packages.
715+
716+
717+
718+The `"dependencies"` array lists the names of your packages, which must match the `"name"` fields in their respective sub-rescript.json files.
719+When you build a package in ReScript, it will use the `"package-specs"` and `"suffix"` settings from the root package.
720+Therefore, it is recommended to place these settings in the root `rescript.json` file and avoid specifying them in local package `rescript.json` files.
721+
722+**Settings from different config files:** When Rewatch builds a package within a monorepo setup, it uses these settings from the root rescript.json:
723+
724+- `"jsx"` (jsx_args, jsx_module_args, jsx_mode_args, jsx_preserve_args)
725+- `"experimental"` (experimental_features_args)
726+- `"package-specs"` (used for implementation_args)
727+- `"suffix"` (used for package output)
728+
729+These settings come from the package's own rescript.json:
730+
731+- `"sources"` (determines which files to compile)
732+- `"dependencies"` (package dependencies)
733+- `"warnings"` (warning_args)
734+- `"compiler-flags"` (bsc_flags)
735+
736+When the root package is built, Rewatch will look for the dependencies inside the `my-monorepo/node_modules` folder.
737+It is expected that `package-1` and `package-2` are available there via a symlink system provided by your node_modules package manager.
738+
739+Note that your root rescript.json is allowed to have a `"sources"` setting.
740+These files will be compiled as expected.
741+
742+## Package `rescript.json` Configuration
743+
744+Each nested rescript.json sets up a specific package.
745+
746+`packages/package-1/rescript.json`:
747+
748+
749+
750+`packages/package-2/rescript.json`:
751+
752+
753+
754+In `package-1`, we show how to use special compiler flags.
755+In `package-2`, we show how to disable warning 27 (unused variable).
756+In both cases, the settings only apply to the package where they are specified.
757+Defining these in the root rescript.json will not affect the packages.
758+There is no inheritance system.
759+
760+Also note the dependencies array in `package-2`, which allows that package to depend on `package-1` within the monorepo.
761+
762+## Building the monorepo
763+
764+From the root directory, you can run all ReScript commands:
765+
766+
767+
768+### Building individual packages
769+
770+You can also run ReScript commands on individual packages instead of the entire monorepo. This is useful when you only want to work on one package.
771+
772+
773+
774+When building a single package, ReScript will use the settings from the root rescript.json as explained in the [Root rescript.json Configuration](#root-rescriptjson-configuration) section above.
775+
776+### Building without a root rescript.json
777+
778+If your node_modules monorepo is set up with symlinks, you can build packages even without a root rescript.json:
779+
780+```
781+my-monorepo/
782+├──node_modules/
783+│ ├── package-1/ # symlinked
784+│ ├── package-2/ # symlinked
785+├── package.json
786+├── packages/
787+│ ├── package-1/
788+│ │ ├── rescript.json
789+│ │ ├── package.json
790+│ │ ├── src/
791+│ ├── package-2/
792+│ │ ├── rescript.json
793+│ │ ├── package.json
794+│ │ ├── src/
795+│ ├── ...
796+```
797+
798+Building `package-2` (which depends on `package-1`) will search up the folder structure to find `package-1`.
799+
800+Example:
801+
802+
803+
804+Internally, Rewatch will look for:
805+
806+- 🔴 `my-monorepo/packages/package-2/node_modules/package-1`
807+- 🔴 `my-monorepo/packages/node_modules/package-1`
808+- ✅ `my-monorepo/node_modules/package-1`
809+
810+This only happens as a last resort if `package-1` is not listed as a (dev-)dependency in a parent `rescript.json`.
811+
812+## Troubleshooting
813+
814+If you're having issues with your monorepo setup, you can use the `-v` flag during build to see what Rewatch detected as the project context:
815+
816+
817+
818+This will show you detailed information about how Rewatch is interpreting your project structure and which configuration files it's using.
819+
820+## Recommendation
821+
822+**The ReScript team strongly recommends using a root `rescript.json` file when setting up monorepos.** While it's technically possible to build packages without one (as shown in the section above), having a root configuration file provides several benefits:
823+
824+- **Consistent settings** across all packages (jsx, experimental features, package-specs, suffix)
825+- **Simplified dependency management** through the root dependencies array
826+- **Better developer experience** with unified build commands from the root
827+- **Easier maintenance** and configuration updates across the entire monorepo
828+
829+The root `rescript.json` approach is the intended and supported way to work with ReScript monorepos.
830+# Build System Overview
831+
832+ReScript comes with a build system, [`rescript`](https://www.npmjs.com/package/rescript), that's fast, lean and used as the authoritative build system of the community.
833+
834+Every ReScript project needs a build description file, `rescript.json`.
835+
836+## Options
837+
838+See `rescript help`:
839+
840+```
841+❯ rescript help
842+Usage: rescript <options> <subcommand>
843+
844+`rescript` is equivalent to `rescript build`
845+
846+Options:
847+ -v, -version display version number
848+ -h, -help display help
849+
850+Subcommands:
851+ build
852+ clean
853+ format
854+ convert
855+ dump
856+ help
857+
858+Run `rescript <subcommand> -h` for subcommand help. Examples:
859+ rescript build -h
860+ rescript format -h
861+```
862+
863+## Build Project
864+
865+Each build will create build artifacts from your project's source files.
866+
867+**To build a project (including its dependencies)**, run:
868+
869+
870+
871+Which is an alias for `rescript build`.
872+
873+To keep a build watcher, run:
874+
875+
876+
877+Any new file change will be picked up and the build will re-run.
878+
879+**Note**: third-party libraries in `node_modules` aren't watched, as doing so may exceed the node.js watcher count limit.
880+
881+For monorepo setup in ReScript 12+, see [Setting up a monorepo](./build-monorepo-setup.mdx).
882+
883+## Clean Project
884+
885+If you ever get into a stale build for edge-case reasons, use:
886+
887+
888+
889+## Compile with stricter errors in CI
890+
891+**Since 11.1**
892+
893+You may want to compile your project with stricter rules for production, than when developing. With the `-warn-error` build flag, this can easily be done, for instance in a continuous integration script. E.g.:
894+
895+
896+
897+Here, warning number 110, which is triggered when a [`%todo`](../../syntax-lookup/extension_todo.mdx) has been found, gets promoted to an error. The full list of warning numbers can be found [here](./warning-numbers.mdx).
898+# Build Performance
899+
900+ReScript considers performance at install time, build time and run time as a serious feature; it's one of those things you don't notice until you realize it's missing.
901+
902+## Profile Your Build
903+
904+Sometime your build can be slow due to some confused infra setups. We provide an interactive visualization of your build's performance via `bstracing`:
905+
906+
907+
908+Run the above command at your ReScript project's root; it'll spit out a JSON file you can drag and drop into `chrome://tracing`.
909+
910+<Image
911+ withShadow={true}
912+ src="/img/bstracing.avif"
913+ className="w-auto mx-auto md:mx-auto"
914+ caption="Screenshot of bstracing result"
915+/>
916+
917+## Under the Hood
918+
919+ReScript itself uses a build system under the hood, called [Ninja](https://ninja-build.org). Ninja is like Make, but cross-platform, minimal, focuses on perf and destined to be more of a low-level building block than a full-blown build system. In this regard, Ninja's a great implementation detail for `rescript`.
920+
921+ReScript reads into `rescript.json` and generates the Ninja build file in `lib/bs`. The file contains the low-level compiler commands, namespacing rules, intermediate artifacts generation & others. It then runs `ninja` for the actual build.
922+
923+## The JS Wrapper
924+
925+`rescript` itself is a Node.js wrapper which takes care of some miscellaneous tasks, plus the watcher. The lower-level, watcher-less, fast native `rescript` is called `rescript.exe`. It's located at `node_modules/rescript/{your-platform}/rescript.exe`.
926+
927+If you don't need the watcher, you can run said `rescript.exe`. This side-steps Node.js' long startup time, which can be in the order of `100ms`. Our editor plugin finds and uses this native `rescript.exe` for better performance.
928+
929+## Numbers
930+
931+Raw `rescript.exe` build on a small project should be around `70ms`. This doubles when you use the JS `rescript` wrapper which comes with a watcher, which is practically faster since you don't manually run the build at every change (though you should opt for the raw `rescript.exe` for programmatic usage, e.g. inserting rescript into your existing JS build pipeline).
932+
933+No-op build (when no file's changed) should be around `15ms`. Incremental rebuild (described soon) of a single file in a project is around `70ms` too.
934+
935+Cleaning the artifacts should be instantaneous.
936+
937+### Extreme Test
938+
939+We've stress-tested `rescript.exe` on a big project of 10,000 files (2 directories, 5000 files each, first 5000 no dependencies, last 5000 10 dependencies on files from the former directory) using https://github.com/rescript-lang/build-benchmark, on a Retina Macbook Pro Early 2015 (3.1 GHz Intel Core i7).
940+
941+{/* TODO: better repro */}
942+
943+- No-op build of 10k files: `800ms` (the minimum amount of time required to check the mtimes of 10k files).
944+- Clean build: \<3 minutes.
945+- Incremental build: depends on the number of the dependents of the file. No dependent means `1s`.
946+
947+### Stability
948+
949+`rescript` is a file-based build system. We don't do in-memory build, even if that speeds up the build a lot. In-memory builds risk memory leaks, out-of-memory errors, corrupt halfway build and others. Our watcher mode stays open for days or months with no leak.
950+
951+The watcher is also just a thin file watcher that calls `rescript.exe`. We don't like babysitting daemon processes.
952+
953+## Incrementality & Correctness
954+
955+ReScript doesn't take whole seconds to run every time. The bulk of the build performance comes from incremental build, aka re-building a previously built project when a few files changed.
956+
957+In short, thanks to our compiler and the build system's architecture, we're able to **only build what's needed**. If `MyFile.res` isn't changed, it isn't recompiled. Renaming or moving files is handled automatically, with no stale builds.
958+
959+## Speed Up Incremental Build
960+
961+ReScript uses the concept of interface files (`.resi`) (or, equivalently, [module signatures](./module.mdx#signatures)). Exposing only what you need naturally speeds up incremental builds. E.g. if you change a `.res` file whose corresponding `.resi` file doesn't expose the changed part, then you've reduced the amount of dependent files you have to rebuild.
962+
963+## Programmatic Usage
964+
965+Unfortunately, JS build systems are usually the bottleneck for building a JS project nowadays. Having parts of the build blazingly fast doesn't matter much if the rest of the build takes seconds or literally minutes. Here are a few suggestions:
966+
967+- Convert more files into ReScript =). Fewer files going through fewer parts of the JS pipeline helps a ton.
968+- Careful with bringing in more dependencies: libraries, syntax transforms (e.g. the unofficially supported PPX), build step loaders, etc. The bulk of these dragging down the editing & building experience might out-weight the API benefits they provide.
969+
970+## Hot Reloading
971+
972+Hot reloading refers to maintaining a dev server and listening to file changes in a way that allows the server to pipe some delta changes right into the currently running browser page. This provides a relatively fast iteration workflow while working in specific frameworks.
973+
974+However, hot reloading is fragile by nature, and counts on the occasional inconsistencies (bad state, bad eval, etc.) and the heavy devserver setup/config being less of a hassle than the benefits it provides. We err on the side of caution and stability in general, and decided not to provide a built-in hot reloading _yet_. **Note**: you can still use the hot reloading facility provided by your JS build pipeline.
975+# If-Else & Loops
976+
977+ReScript supports `if`, `else`, ternary expression (`a ? b : c`), `for` and `while`.
978+
979+The `switch` pattern supports a default case. Read more about [pattern-matching & destructuring](./pattern-matching-destructuring.mdx).
980+
981+## If-Else & Ternary
982+
983+ReScript's `if` is an expression; it evaluates to its body's content:
984+
985+
986+
987+**Note:** an `if-else` expression without the final `else` branch implicitly gives `()` (aka the `unit` type). So this:
988+
989+
990+
991+is basically the same as:
992+
993+
994+
995+Here's another way to look at it. This is clearly wrong:
996+
997+
998+
999+It'll give a type error, saying basically that the implicit `else` branch has the type `unit` while the `if` branch has type `int`. Intuitively, this makes sense: what would `result`'s value be, if `showMenu` was `false`?
1000+
1001+We also have ternary sugar, but **we encourage you to prefer if-else when possible**.
1002+
1003+
1004+
1005+`if-else` and ternary are often replaced by [pattern matching](./pattern-matching-destructuring.mdx), which handles a wide range of conditional logic more expressively.
1006+
1007+## For Loops
1008+
1009+For loops iterate from a starting value up to (and including) the ending value.
1010+
1011+
1012+
1013+
1014+
1015+You can make the `for` loop count in the opposite direction by using `downto`.
1016+
1017+
1018+
1019+
1020+
1021+## While Loops
1022+
1023+While loops execute its body code block while its condition is true.
1024+
1025+
1026+
1027+### Tips & Tricks
1028+
1029+There's no loop-breaking `break` keyword (nor early `return` from functions, for that matter) in ReScript. However, we can break out of a while loop easily through using a [mutable binding](./mutation.mdx).
1030+
1031+
1032+# Converting from JS
1033+
1034+If you want a quick syntax guide before starting a migration, see [ReScript for JavaScript Developers](./rescript-for-javascript-developers.mdx).
1035+
1036+ReScript offers a unique project conversion methodology which:
1037+
1038+- Ensures minimal disruption to your teammates (very important!).
1039+- Remove the typical friction of verifying conversion's correctness and performance guarantees.
1040+- Doesn't require pre-made binding libraries. You can write bindings directly for any JavaScript API.
1041+
1042+## Step 1: Install ReScript
1043+
1044+Run `npm install rescript` on your project, then imitate our [New Project](./installation.mdx#new-project) workflow by adding a `rescript.json` at the root. Then start `npx rescript -w`.
1045+
1046+## Step 2: Copy Paste the Entire JS File
1047+
1048+Let's work on converting a file called `src/main.js`.
1049+
1050+
1051+
1052+First, copy the entire file content over to a new file called `src/Main.res` by using our [`%%raw` JS embedding trick](./embed-raw-javascript.mdx):
1053+
1054+
1055+
1056+Add this file to `rescript.json`:
1057+
1058+
1059+
1060+Open an editor tab for `src/Main.res.js`. Do a command-line `diff -u src/main.js src/Main.res.js`. Aside from whitespaces, you should see only minimal, trivial differences. You're already a third of the way done!
1061+
1062+**Always make sure** that at each step, you keep the ReScript output `.res.js` file open to compare against the existing JavaScript file. Our compilation output is very close to your hand-written JavaScript; you can simply eye the difference to catch conversion bugs!
1063+
1064+## Step 3: Extract Parts into Idiomatic ReScript
1065+
1066+Let's turn the `defaultId` variable into a ReScript let-binding:
1067+
1068+
1069+
1070+Check the output. Diff it. Code still works. Moving on! Extract the function:
1071+
1072+
1073+
1074+Format the code: `./node_modules/.bin/rescript format src/Main.res`.
1075+
1076+We have a type error: "The record field student can't be found". That's fine! **Always ensure your code is syntactically valid first**. Fixing type errors comes later.
1077+
1078+## Step 4: Add externals, Fix Types
1079+
1080+The previous type error is caused by `payload`'s record declaration (which supposedly contains the field `student`) not being found. Since we're trying to convert as quickly as possible, let's use our [object](./object.mdx) feature to avoid needing type declaration ceremonies:
1081+
1082+
1083+
1084+Now this triggers the next type error, that `school` isn't found. Let's use [`external`](./external.mdx) to bind to that module:
1085+
1086+
1087+
1088+We hurrily typed `school` as a polymorphic `'whatever` and let its type be inferred by its usage below. The inference is technically correct, but within the context of bringing it a value from JavaScript, slightly dangerous. This is just the interop trick we've shown in the [`external`](./external.mdx) page.
1089+
1090+Anyway, the file passes the type checker again. Check the `.res.js` output, diff with the original `.js`; we've now converted a file over to ReScript!
1091+
1092+Now, you can delete the original, hand-written `main.js` file, and grep the files importing `main.js` and change them to importing `Main.res.js`.
1093+
1094+## (Optional) Step 5: Cleanup
1095+
1096+If you prefer more advanced, rigidly typed `payload` and `school`, feel free to do so:
1097+
1098+
1099+
1100+We've:
1101+
1102+- introduced an opaque types for `school` and `student` to prevent misuse of their values
1103+- typed the payload as a record with only the `student` field
1104+- typed `getStudentById` as the sole method of `student`
1105+
1106+Check that the `.res.js` output didn't change. How rigidly to type your JavaScript code is up to you; we recommend not typing them too elaborately; it's sometime an endless chase, and produces diminishing returns, especially considering that the elaborate-ness might turn off your potential teammates.
1107+
1108+## Tips & Tricks
1109+
1110+In the same vein of idea, **resist the urge to write your own wrapper functions for the JS code you're converting**. Use [`external`s](./external.mdx), which are guaranteed to be erased in the output. And avoid trying to take the occasion to convert JS data structures into ReScript-specific data structures like variant or list. **This isn't the time for that**.
1111+
1112+The moment you produce extra conversion code in the output, your skeptical teammate's mental model might switch from "I recognize this output" to "this conversion might be introducing more problems than it solves. Why are we testing ReScript again?". Then you've lost.
1113+
1114+## Conclusion
1115+
1116+- Paste the JS code into a new ReScript file as embedded raw JS code.
1117+- Compile and keep the output file open. Check and diff against original JS file. Free regression tests.
1118+- Always make sure your file is syntactically valid. Don't worry about fixing types before that.
1119+- (Ab)use [object](./object.mdx) accesses to quickly convert things over.
1120+- Optionally clean up the types for robustness.
1121+- Don't go overboard and turn off your boss and fellow teammates.
1122+- Proudly display that you've conserved the semantics and performance characteristics during the conversion by showing your teammates the eerily familiar output.
1123+- Get promoted for introducing a new technology the safer, mature way.
1124+# Dictionary
1125+
1126+ReScript has first class support for dictionaries. Dictionaries are mutable objects with string keys, where all values must have the same type. Dicts compile to regular JavaScript objects at runtime.
1127+
1128+## Create
1129+
1130+You can create a new dictionary in a few different ways, depending on your use case.
1131+
1132+
1133+
1134+A few things to note here:
1135+
1136+- Using the first class `dict{}` syntax compiles cleanly to a JavaScript object directly
1137+- Using `Dict.fromArray` is useful when you need to create a dictionary programatically
1138+
1139+## Access
1140+
1141+You can access values from a Dictionary either via the the standard library `Dict` module functions, or using pattern matching.
1142+
1143+
1144+
1145+> In the Destructuring example, we're using the `?` optional pattern match syntax to pull out the `C` key value as an optional, regardless of if the dict has it or not.
1146+
1147+## Pattern matching
1148+
1149+Dictionaries have first class support for pattern matching. Read more in the [dedicated guide on pattern matching and destructring in ReScript](./pattern-matching-destructuring.mdx#match-on-dictionaries).
1150+
1151+## Updating and setting values
1152+
1153+You can set and update new values on your dictionary using the `Dict.set` function. All updates are mutable.
1154+
1155+
1156+
1157+## Advanced example: Pattern matching on JSON
1158+
1159+JSON objects are represented as dictionaries (`dict<JSON.t>`). You can leverage that fact to decode JSON in a nice way, using only language features:
1160+
1161+
1162+# Dead Code Analysis in ReScript
1163+
1164+This guide provides a detailed walkthrough on how to leverage ReScript’s powerful dead code analysis tools to maintain a clean, efficient, and distraction-free codebase.
1165+
1166+Dead code refers to code that's present in your codebase but is never executed. It can lead to:
1167+
1168+- Increased compilation times
1169+- Confusion during development
1170+- Misleading assumptions about functionality
1171+
1172+ReScript’s language design allows for accurate and efficient dead code analysis using the **ReScript Code Analyzer**, available via the official VSCode extension.
1173+
1174+### Prerequisites
1175+
1176+- ReScript VSCode extension (v1.8.2 or higher)
1177+
1178+### Activation
1179+
1180+1. Open the Command Palette: `Cmd/Ctrl + P`
1181+2. Run: `> ReScript: Start Code Analyzer`
1182+
1183+### Deactivation
1184+
1185+- Run: `> ReScript: Stop Code Analyzer`
1186+- Or click “Stop Code Analyzer” in the status bar
1187+
1188+### Result
1189+
1190+- The “Problems” pane populates with dead code warnings and suggestions.
1191+
1192+### Reactive Updates (New)
1193+
1194+Reactive dead code updates are a newer enhancement of Editor Code Analysis and require ReScript VSCode extension v1.73.9 or higher (pre-release).
1195+
1196+## Real-World Use Cases
1197+
1198+### 1. **Unused Record Fields**
1199+
1200+
1201+
1202+Remove unused fields to simplify code.
1203+
1204+### 2. **Unused Variant Cases**
1205+
1206+
1207+
1208+Removing unused variants allows simplifying rendering logic.
1209+
1210+### 3. **Unused Parts of State**
1211+
1212+
1213+
1214+Old validation logic might remain after refactors—clean it up.
1215+
1216+### 4. **Unnecessary Interface Exposure**
1217+
1218+
1219+
1220+Keep interfaces minimal by removing unused exports.
1221+
1222+### 5. **Unused Functions**
1223+
1224+
1225+
1226+Removing these often uncovers further unused logic.
1227+
1228+### 6. **Unused Components**
1229+
1230+Components never referenced in production should be removed, unless explicitly preserved.
1231+
1232+## Keeping Some Dead Code
1233+
1234+### Use `@dead` and `@live`
1235+
1236+#### `@dead`
1237+
1238+Suppresses warnings but notifies if code becomes alive again.
1239+
1240+
1241+
1242+#### `@live`
1243+
1244+Permanently marks code as alive (no future warnings).
1245+
1246+
1247+
1248+## Configuration
1249+
1250+Add to your `rescript.json`:
1251+
1252+
1253+
1254+### Options:
1255+
1256+- **analysis**: Enables dead code analysis (`"dce"`)
1257+- **suppress**: Silences reporting for paths (still analyzes)
1258+- **unsuppress**: Re-enables reports within suppressed paths
1259+- **transitive**: Controls reporting of indirectly dead code
1260+
1261+**Recommendation:** Set `transitive: false` for incremental cleanup.
1262+
1263+## Summary
1264+
1265+ReScript’s dead code analyzer helps you:
1266+
1267+- Incrementally clean up your codebase
1268+- Avoid confusion and complexity
1269+- Improve long-term maintainability
1270+
1271+Use it regularly for the best results.
1272+# Editor
1273+
1274+This section is about the editor plugin for ReScript. It adds syntax highlighting, autocomplete, type hints, formatting, code navigation, code analysis for `.res` and `.resi` files.
1275+
1276+## Plugins
1277+
1278+- [VSCode](https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode)
1279+- [Sublime Text](https://github.com/rescript-lang/rescript-sublime)
1280+- [Vim/Neovim](https://github.com/rescript-lang/vim-rescript)
1281+
1282+### Community Supported
1283+
1284+We don't officially support these; use them at your own risk!
1285+
1286+- [Neovim Tree-sitter](https://github.com/nkrkv/nvim-treesitter-rescript)
1287+- [IDEA](https://github.com/reasonml-editor/reasonml-idea-plugin)
1288+- [Emacs](https://github.com/jjlee/rescript-mode)
1289+
1290+## Code analysis
1291+
1292+The code analysis provides extra checks for your ReScript project, such as detecting dead code and unhandled exceptions. It's powered by [reanalyze](https://github.com/rescript-association/reanalyze), which is built into the extension — no separate install required.
1293+
1294+### How to Use
1295+
1296+- Open the command palette and run:
1297+ `ReScript: Start Code Analyzer`
1298+- Warnings like dead code will show inline in the editor.
1299+- Suppression actions are available where applicable.
1300+- To stop analysis, click **Stop Code Analyzer** in the status bar.
1301+
1302+### Configuration
1303+
1304+Add a `reanalyze` section to your `rescript.json` to control what the analyzer checks or ignores. You'll get autocomplete for config options in the editor.
1305+More details: [reanalyze configuration docs](https://github.com/rescript-association/reanalyze#configuration-via-bsconfigjson)
1306+
1307+### Exception analysis
1308+
1309+The exception analysis is designed to keep track statically of the exceptions that might be thrown at runtime. It works by issuing warnings and recognizing annotations. Warnings are issued whenever an exception is thrown and not immediately caught. Annotations are used to push warnings from he local point where the exception is thrown, to the outside context: callers of the current function.
1310+Nested functions need to be annotated separately.
1311+
1312+Instructions on how to run the exception analysis using the `-exception` and `-exception-cmt` command-line arguments, or how to add `"analysis": ["exception"]` in `rescript.json` are contained in the [reanalyze configuration docs](https://github.com/rescript-association/reanalyze#configuration-via-bsconfigjson).
1313+
1314+Here's an example, where the analysis reports a warning any time an exception is thrown, and not caught:
1315+
1316+
1317+
1318+reports:
1319+
1320+
1321+
1322+No warning is reported when a `@throws` annotation is added:
1323+
1324+
1325+
1326+When a function throws multiple exceptions, a tuple annotation is used:
1327+
1328+
1329+
1330+It is possible to silence the analysis by adding a `@doesNotThrow` annotation:
1331+
1332+
1333+
1334+#### Limitations
1335+
1336+- The libraries currently modeled are limited to the standard library, Belt and Js modules. Models are currently vendored in the analysis, and are easy to add (see [`analysis/reanalyze/src/ExnLib.ml`](https://github.com/rescript-lang/rescript/blob/master/analysis/reanalyze/src/ExnLib.ml))
1337+- Generic exceptions are not understood by the analysis. For example `exn` is not recognized below (only concrete exceptions are):
1338+
1339+
1340+
1341+- Uses of e.g. `List.head` are interpreted as belonging to the standard library. If you re-define `List` in the local scope, the analysis it will think it's dealing with `List` from the standard library.
1342+- There is no special support for module functions.
1343+
1344+### Guide
1345+
1346+Look - [Editor Code Analysis](./editor-code-analysis.mdx) for a more detailed guide about how to use the code analysis tool.
1347+
1348+### Caveats
1349+
1350+- For older extension versions, cross-package dead code analysis in monorepos may be limited.
1351+
1352+## Editor features
1353+
1354+Below are features and configurations of the editor tooling that might be good to know about.
1355+
1356+### Pipe completions
1357+
1358+Pipes (`->`) are a huge and important part of the ReScript language, for many reasons. Because of that, extra care has gone into the editor experience for using pipes.
1359+
1360+#### Default pipe completion rules for non-builtin types
1361+
1362+By default, using `->` will give completions from the module where the type of the expression you're piping on is defined. So, if you're piping on something of the type `SomeModule.t` (like `someValue->`) then you'll get completions for all functions defined in `SomeModule` that take the type `t` as the first unlabelled argument.
1363+
1364+#### Pipe completions for builtin types
1365+
1366+For builtin types, completion will automatically happen based on the _standard library module_ for that type. So, `array` types will get completions from the `Array` module, `string` gets completions from `String`, and so on.
1367+
1368+There is a way to enhance this behavior via configuration, described further down in this document.
1369+
1370+### Dot completion enhancements
1371+
1372+In ReScript, using a dot (`.`) normally means "access record field". The editor extends dot (`.`) to trigger completions in more scenarios beyond record field access.
1373+
1374+This behavior has the following important implications:
1375+
1376+- Improves discoverability (E.g. using a `.` will reveal important pipe completions)
1377+
1378+Below is a list of all the scenarios where using dots trigger completion in addition to the normal record field completion.
1379+
1380+#### Objects
1381+
1382+When writing a `.` on something that's a [structural object](./object.mdx), you'll get completions for those object properties. Example:
1383+
1384+
1385+
1386+#### Pipe completions for anything
1387+
1388+When writing `.` on _anything_, the editor will try to do pipe completion for the value on the left of the `.`. Example:
1389+
1390+
1391+
1392+### `@editor.completeFrom` for drawing completions from additional modules
1393+
1394+You can configure any type you have control over to draw pipe completions from additional modules, in addition to the main module where the type is defined, via the `@editor.completeFrom` decorator. This is useful in many different scenarios:
1395+
1396+- When you, for various reasons, need to have your type definition separate from its "main module". Could be because of cyclic dependencies, a need for the type to be in a recursive type definition chain, and so on.
1397+- You have separate modules with useful functions for your type but that you don't want to (or can't) include in the main module of that type.
1398+
1399+Let's look at an example:
1400+
1401+
1402+
1403+In the example above, if we try and pipe on something of the type `Types.htmlInput`, we'll get no completions because there are no functions in `Types` that take `htmlInput` as its first unlabelled argument. But, better DX would be for the editor to draw completions from our util functions for `htmlInput` in the `Utils.HtmlInput` module.
1404+
1405+With `@editor.completeFrom`, we can fix this. Let's look at an updated example:
1406+
1407+
1408+
1409+Now when piping on a value of the type `Types.htmlInput`, the editor tooling will know to include relevant functions from the module `Utils.HtmlInput`, and you'll get the completions you expect, even if the functions aren't located in the same module.
1410+
1411+> You can point out multiple modules to draw completions from for a type either by repeating `@editor.completeFrom` with a single module path each time, or by passing an array with all the module paths you want to include, like `@editor.completeFrom([Utils.HtmlInput, HtmlInputUtils])`.
1412+
1413+### Configuring the editor via `editor` in `rescript.json`
1414+
1415+There's certain configuration you can do for the editor on a per project basis in `rescript.json`. Below lists all of the configuration available.
1416+
1417+#### `autocomplete` for pipe completion
1418+
1419+The `autocomplete` property of `editor` in `rescript.json` let's you map types to modules _on the project level_ that you want the editor to leverage when doing autocomplete for pipes.
1420+
1421+This is useful in scenarios like:
1422+
1423+- You have your own util module(s) for builtin types. Maybe you have an `ArrayExtra` with helpers for arrays that you want to get completions from whenever dealing with arrays.
1424+- You have your own util module(s) for types you don't control yourself (and therefore can't use `@editor.completeFrom`), like from external packages you install.
1425+
1426+To configure, you pass `autocomplete` an object where the keys are the _path to the type_ you want to target, and then an array of the path to each module you want to include for consideration for pipe completions.
1427+
1428+Let's take two examples.
1429+
1430+##### Enhancing completion for builtin types
1431+
1432+First, let's look at including our own `ArrayExtra` in all completions for `array`:
1433+
1434+
1435+
1436+Now, when using pipes on arrays, you'll get completions both from the standard library array functions, and also from your own `ArrayExtra` module.
1437+
1438+
1439+
1440+**Note**: generic types like `promise.t` and `result.t` do not need any additional types in the `rescript.json`:
1441+
1442+
1443+
1444+##### Enhancing completion for non-builtin types
1445+
1446+Now, let's look at an example of when you have a non-builtin type that you don't have control over.
1447+
1448+In this example, imagine this:
1449+
1450+- We're writing an app using `fastify`
1451+- We're using an external package that provides the necessary bindings in a `Fastify` module
1452+- We've got our own extra file `FastifyExtra` that has various custom util functions that operate on the main type `Fastify.t`
1453+
1454+We now want the editor to always suggest completions from the `FastifyExtra` module, in addition to the regular completions from the main `Fastify` module.
1455+
1456+Let's configure this using the `editor.autocomplete` config in `rescript.json`:
1457+
1458+
1459+
1460+Now, when using pipes on anything of type `Fastify.t`, we'll also get completions from our custom `FastifyExtra`.
1461+
1462+##### Enhancing completion for non-builtin types with namespaces
1463+
1464+When a project uses a namespace, this affects the internal representation of type names used in the `autocomplete` configuration.
1465+
1466+Consider the [geolocation](https://rescript-lang.github.io/experimental-rescript-webapi/apidocs/geolocation-api/#geolocation) type from the [Experimental WebAPI bindings](https://rescript-lang.github.io/experimental-rescript-webapi/).
1467+This project specifies in its `rescript.json`:
1468+
1469+
1470+
1471+This makes the `geolocation` type internally represented as `GeolocationAPI-WebAPI.geolocation`, where:
1472+
1473+- `GeolocationAPI` is the module name
1474+- `WebAPI` is the namespace
1475+- `geolocation` is the type name
1476+
1477+**Important**: You must use this internal representation when configuring autocomplete for namespaced types:
1478+
1479+
1480+# Embed Raw JavaScript
1481+
1482+## Paste Raw JS Code
1483+
1484+First thing first. If you're ever stuck learning ReScript, remember that you can always just paste raw JavaScript code into our source file:
1485+
1486+
1487+
1488+The `%%raw` special ReScript call takes your code string and pastes it as-is into the output. **You've now technically written your first ReScript file!**
1489+
1490+(The backtick syntax is a multiline string. No escaping is needed inside the string.)
1491+
1492+While `%%raw` lets you embed top-level raw JS code, `%raw` lets you embed expression-level JS code:
1493+
1494+
1495+
1496+The above code:
1497+
1498+- declared a ReScript variable `add`,
1499+- with the raw JavaScript value of a function declaration,
1500+- then called that function in ReScript.
1501+
1502+Existing JavaScript code can live inside ReScript files during migration.
1503+
1504+## Debugger
1505+
1506+You can also drop a `%debugger` expression in a body:
1507+
1508+
1509+
1510+Output:
1511+
1512+
1513+
1514+## Tips & Tricks
1515+
1516+Embedding raw JS snippets isn't the best way to experience ReScript, though it's also highly useful if you're just starting out. As a matter of fact, the first few ReScript projects were converted through:
1517+
1518+- pasting raw JS snippets inside a file
1519+- examining the JS output (identical to the old hand-written JS)
1520+- gradually extract a few values and functions and making sure the output still looks OK
1521+
1522+At the end, we get a fully safe, converted ReScript file whose JS output is clean enough that we can confidently assert that no new bug has been introduced during the conversion process.
1523+
1524+See the [Converting from JS](./converting-from-js.mdx) guide for a detailed walkthrough.
1525+# Equality and Comparison
1526+
1527+ReScript has shallow equality `===`, deep equality `==`, and comparison operators `>`, `>=`, `<`, and `<=`.
1528+
1529+## Shallow equality
1530+
1531+The shallow equality operator `===` compares two values and either compiles to `===` or a `bool` if the equality is known to the compiler.
1532+It behaves the same as the strict equality operator `===` in JavaScript.
1533+
1534+Using `===` will never add a runtime cost.
1535+
1536+
1537+
1538+## Deep equality
1539+
1540+ReScript has the deep equality operator `==` to check deep equality of two items, which is very different from the loose equality operator like `==` in JavaScript.
1541+
1542+When using `==` in ReScript it will never compile to `==` in JavaScript,
1543+it will either compile to `===`, a runtime call to an internal function that deeply compares the equality, or a `bool` if the equality is known to the compiler.
1544+
1545+
1546+
1547+`==` will compile to `===` (or a `bool` if the compiler can determine equality) when:
1548+
1549+- Comparing `string`, `char`, `int`, `float`, `bool`, or `unit`
1550+- Comparing variants or polymorphic variants that do not have constructor values
1551+
1552+`==` will compile to a runtime check for deep equality when:
1553+
1554+- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression `Re.t`
1555+- Comparing variants or polymorphic variants that have constructor values
1556+
1557+> When using `==` pay close attention to the JavaScript output if you're not sure what `==` will compile to.
1558+
1559+## Comparison
1560+
1561+ReScript has operators for comparing values that compile to the the same operator in JS, a runtime check using an internal function, or a `bool` if the equality is known to the compiler,
1562+
1563+| operator | comparison |
1564+| -------- | --------------------- |
1565+| `>` | greater than |
1566+| `>=` | greater than or equal |
1567+| `<` | less than |
1568+| `<=` | less than or equal |
1569+
1570+Comparison can be done on any type.
1571+
1572+An operator will compile to the same operator (or a `bool` if the compiler can determine equality) when:
1573+
1574+- Comparing `int`, `float`, `string`, `char`, `bool`
1575+
1576+An operator will compile to a runtime check for deep equality when:
1577+
1578+- Comparing `array`, `tuple`, `list`, `object`, `record`, or regular expression (`Re.t`)
1579+- Comparing variants or polymorphic variants
1580+
1581+
1582+
1583+## Performance of runtime equality checks
1584+
1585+The runtime equality check ReScript uses is quite fast and should be adequate for almost all use cases.
1586+For small objects it can be 2x times faster than alternative deep compare functions such as Lodash's [`_.isEqual`](https://lodash.com/docs/4.17.15#isEqual).
1587+
1588+For larger objects instead of using `==` you could manually use a faster alternative such as [fast-deep-compare](https://www.npmjs.com/package/fast-deep-equal), or write a custom comparator function.
1589+
1590+[This repo](https://github.com/jderochervlk/rescript-perf) has benchmarks comparing results of different libraries compared to ReScript's built-in equality function.
1591+# Exception
1592+
1593+Exceptions are just a special kind of variant, thrown in **exceptional** cases (don't abuse them!). Consider using the [`option`](./null-undefined-option.mdx) or [`result`](/docs/manual/api/stdlib/result) type for recoverable errors.
1594+
1595+You can create your own exceptions like you'd make a variant (exceptions need to be capitalized too).
1596+
1597+
1598+
1599+## Built-in Exceptions
1600+
1601+ReScript has some built-in exceptions:
1602+
1603+### `Not_found`
1604+
1605+
1606+
1607+Note that the above is just for demonstration purposes; in reality, you'd return an `option<int>` directly from `getItem` and avoid the `try` altogether.
1608+
1609+You can directly match on exceptions _while_ getting another return value from a function:
1610+
1611+
1612+
1613+### `Invalid_argument`
1614+
1615+Used to check if argument is valid. This exception takes a string.
1616+
1617+
1618+
1619+### `Assert_failure`
1620+
1621+Thrown when you use `assert(condition)` and `condition` is false. The arguments
1622+are the location of the `assert` in the source code (file name, line number, column number).
1623+
1624+
1625+
1626+### `Failure`
1627+
1628+Exception thrown to signal that the given arguments do not make sense. This
1629+exception takes a string as an argument.
1630+
1631+
1632+
1633+### `Division_by_zero`
1634+
1635+Exception thrown by integer division and remainder operations when their second argument is zero.
1636+
1637+
1638+
1639+## Catching JS Exceptions
1640+
1641+To distinguish between JavaScript exceptions and ReScript exceptions, ReScript namespaces JS exceptions under the `JsExn(payload)` variant. To catch an exception thrown from the JS side:
1642+
1643+Throw an exception from JS:
1644+
1645+
1646+
1647+Then catch it from ReScript:
1648+
1649+
1650+
1651+The payload `exn` here is of type `unknown` since in JS you can throw anything. To operate on `exn`, do like the code above by using the standard library's [`JsExn`](/docs/manual/api/stdlib/jsexn) module's helpers
1652+or use [`Type.Classify.classify`](/docs/manual/api/stdlib/type/classify#value-classify) to get more information about the runtime type of `exn`.
1653+
1654+## Throw a JS Exception
1655+
1656+### Throw a JS Error
1657+
1658+`throw(MyException)` throws a ReScript exception. To throw a JavaScript error (whatever your purpose is), use `JsError.throwWithMessage`:
1659+
1660+
1661+
1662+Then you can catch it from the JS side:
1663+
1664+
1665+
1666+### Throw a value that is not an JS Error
1667+
1668+If you want to throw any value that is not a valid JS Error, use `JsExn.throw`:
1669+
1670+
1671+
1672+Then you can catch it from the JS side:
1673+
1674+
1675+
1676+## Catch ReScript Exceptions from JS
1677+
1678+To let JavaScript code work with exception-throwing ReScript code, you don't need to throw a JS exception. ReScript exceptions can be used directly from JavaScript.
1679+
1680+
1681+
1682+Then, in your JS:
1683+
1684+
1685+
1686+The above `BadArgument` exception takes an inline record type. We special-case compile the exception as `{RE_EXN_ID, myMessage, Error}` for good ergonomics. If the exception instead took ordinary positional arguments, l like the standard library's `Invalid_argument("Oops!")`, which takes a single argument, the argument is compiled to JS as the field `_1` instead. A second positional argument would compile to `_2`, etc.
1687+
1688+## Tips & Tricks
1689+
1690+When you have ordinary variants, you often don't **need** exceptions. For example, instead of throwing when `item` can't be found in a collection, try to return an `option<item>` (`None` in this case) instead.
1691+
1692+### Catch Both ReScript and JS Exceptions in the Same `catch` Clause
1693+
1694+
1695+
1696+This technically works, but hopefully you don't ever have to work with such code...
1697+# Extensible Variant
1698+
1699+Variant types are usually constrained to a fixed set of constructors. There may be very rare cases where you still want to be able to add constructors to a variant type even after its initial type declaration. For this, we offer extensible variant types.
1700+
1701+## Definition and Usage
1702+
1703+
1704+
1705+The `..` in the type declaration above defines an extensible variant `type t`. The `+=` operator is then used to add constructors to the given type.
1706+
1707+**Note:** Don't forget the leading `type` keyword when using the `+=` operator!
1708+
1709+## Pattern Matching Caveats
1710+
1711+Extensible variants are open-ended, so the compiler will not be able to exhaustively pattern match all available cases. You will always need to provide a default `_` case for every `switch` expression.
1712+
1713+
1714+
1715+## Tips & Tricks
1716+
1717+**Fun fact:** Like [exception](./exception.mdx), extensible variant It's one of the very few use-case where extensible variants make sense.
1718+
1719+We usually recommend sticking with common [variants](./variant.mdx) as much as possible to reap the benefits of exhaustive pattern matching.
1720+# External (Bind to Any JS Library)
1721+
1722+`external` is the primary ReScript feature for bringing in and using JavaScript values.
1723+
1724+`external` is like a let binding, but:
1725+
1726+- The right side of `=` isn't a value; it's the name of the JS value you're referring to.
1727+- The type for the binding is mandatory, since we need to know what the type of that JS value is.
1728+- Can only exist at the top level of a file or module.
1729+
1730+
1731+
1732+There are several kinds of `external`s, differentiated and/or augmented through the [attribute](./attribute.mdx) they carry. This page deals with the general, shared mechanism behind most `external`s. The different `external`s are documented in their respective pages later. A few notable ones:
1733+
1734+- `@val`, `@scope`: [bind to global JS values](./bind-to-global-js-values.mdx).
1735+- `@module`: [bind to JS imported/exported values](./import-from-export-to-js.mdx).
1736+- `@send`: [bind to JS methods](./bind-to-js-function.mdx).
1737+
1738+You can also use our [Syntax Lookup](../../syntax-lookup/) tool to find them.
1739+
1740+Related: See our [interop cheatsheet](./interop-cheatsheet.mdx) for an overview.
1741+
1742+## Usage
1743+
1744+Once declared, you can use an `external` as a normal value, just like a let binding.
1745+
1746+## Tips & Tricks
1747+
1748+`external` + ReScript objects are a wonderful combination for quick prototyping. Check the JS output tab:
1749+
1750+
1751+
1752+We've specified `document`'s type as `'a`, a placeholder type that's polymorphic. Any value can be passed there, so you're not getting much type safety (except the inferences at various call sites). This is useful for quickly getting started with a JavaScript library in ReScript since you can write bindings directly for any API you need.
1753+
1754+For more rigidly typed bindings, see the other interop pages in this section.
1755+
1756+## Performance & Output Readability
1757+
1758+`external`s declarations are inlined into their callers during compilation, **and completely disappear from the JS output**. This means any time you use one, you can be sure that you're not incurring extra JavaScript \<-> ReScript conversion cost.
1759+
1760+Additionally, no extra ReScript-specific runtime is better for output readability.
1761+
1762+> **Note:** do also use `external`s and the `@blabla` attributes in the interface files. Otherwise the inlining won't happen.
1763+
1764+## Design Decisions
1765+
1766+ReScript takes interoperating with existing code very seriously. Our type system has very strong guarantees. However, such strong feature also means that, without a great interop system, it'd be very hard to gradually convert a codebase over to ReScript. Fortunately, our interop are comprehensive and cooperate very well with most existing JavaScript code.
1767+
1768+The combination of a sound type system + great interop means that we get the benefits of a traditional gradual type system regarding incremental codebase coverage & conversion, without the downside of such gradual type system: complex features to support existing patterns, slow analysis, diminishing return in terms of type coverage, etc.
1769+# Function
1770+
1771+_Cheat sheet for the full function syntax at the end_.
1772+
1773+ReScript functions are declared with an arrow and return an expression. They compile to clean JavaScript functions.
1774+
1775+
1776+
1777+This declares a function and assigns to it the name `greet`.
1778+
1779+When ReScript can evaluate a known pure function call ahead of time, it can emit the resulting data directly:
1780+
1781+
1782+
1783+Multi-arguments functions have arguments separated by comma:
1784+
1785+If all the arguments are known up front, ReScript can precompute the result too:
1786+
1787+
1788+
1789+For longer functions, you'd surround the body with a block:
1790+
1791+
1792+
1793+If your function has no argument, just write `let greetMore = () => {...}`.
1794+
1795+## Labeled Arguments
1796+
1797+Multi-arguments functions, especially those whose arguments are of the same type, can be confusing to call.
1798+
1799+
1800+
1801+You can attach labels to an argument by prefixing the name with the `~` symbol:
1802+
1803+
1804+
1805+You can provide the arguments in **any order**:
1806+
1807+
1808+
1809+The `~x` part in the declaration means the function accepts an argument labeled `x` and can refer to it in the function body by the same name. You can also refer to the arguments inside the function body by a different name for conciseness:
1810+
1811+
1812+
1813+As a matter of fact, `(~radius)` is just a shorthand for `(~radius as radius)`.
1814+
1815+Here's the syntax for typing the arguments:
1816+
1817+
1818+
1819+## Optional Labeled Arguments
1820+
1821+Labeled function arguments can be made optional during declaration. You can then omit them when calling the function.
1822+
1823+
1824+
1825+When given in this syntax, `radius` is **wrapped** in the standard library's `option` type, defaulting to `None`. If provided, it'll be wrapped with a `Some`. So `radius`'s type value is `None | Some(int)` here.
1826+
1827+Unlike [nullable](./null-undefined-option.mdx), optional fields don't
1828+
1829+### Signatures and Type Annotations
1830+
1831+Functions with optional labeled arguments can be confusing when it comes to signature and type annotations. Indeed, the type of an optional labeled argument looks different depending on whether you're calling the function, or working inside the function body. Outside the function, a raw value is either passed in (`int`, for example), or left off entirely. Inside the function, the parameter is always there, but its value is an option (`option<int>`). This means that the type signature is different, depending on whether you're writing out the function type, or the parameter type annotation. The first being a raw value, and the second being an option.
1832+
1833+If we get back to our previous example and both add a signature and type annotations to its argument, we get this:
1834+
1835+
1836+
1837+The first line is the function's signature, we would define it like that in an interface file (see [Signatures](./module.mdx#signatures)). The function's signature describes the types that the **outside world** interacts with, hence the type `int` for `radius` because it indeed expects an `int` when called.
1838+
1839+In the second line, we annotate the arguments to help us remember the types of the arguments when we use them **inside** the function's body, here indeed `radius` will be an `option<int>` inside the function.
1840+
1841+So if you happen to struggle when writing the signature of a function with optional labeled arguments, try to remember this!
1842+
1843+### Explicitly Passed Optional
1844+
1845+Sometimes, you might want to forward a value to a function without knowing whether the value is `None` or `Some(a)`. Naively, you'd do:
1846+
1847+
1848+
1849+This quickly gets tedious. We provide a shortcut:
1850+
1851+
1852+
1853+This means "I understand `radius` is optional, and that when I pass it a value it needs to be an `int`, but I don't know whether the value I'm passing is `None` or `Some(val)`, so I'll pass you the whole `option` wrapper".
1854+
1855+### Optional with Default Value
1856+
1857+Optional labeled arguments can also be provided a default value. In this case, they aren't wrapped in an `option` type.
1858+
1859+
1860+
1861+## Recursive Functions
1862+
1863+ReScript chooses the sane default of preventing a function to be called recursively within itself. To make a function recursive, add the `rec` keyword after the `let`:
1864+
1865+
1866+
1867+A simple recursive function may look like this:
1868+
1869+
1870+
1871+Recursively calling a function is bad for performance and the call stack. However, ReScript intelligently compiles [tail recursion](https://stackoverflow.com/questions/33923/what-is-tail-recursion) into a fast JavaScript loop. Try checking the JS output of the above code!
1872+
1873+### Mutually Recursive Functions
1874+
1875+Mutually recursive functions start like a single recursive function using the
1876+`rec` keyword, and then are chained together with `and`:
1877+
1878+
1879+
1880+## Partial Application
1881+
1882+**Since 11.0**
1883+
1884+To partially apply a function, use the explicit `...` syntax.
1885+
1886+
1887+
1888+## Async/Await
1889+
1890+Just as in JS, an async function can be declared by adding `async` before the definition, and `await` can be used in the body of such functions.
1891+The output looks like idiomatic JS:
1892+
1893+
1894+
1895+The return type of `getUser` is inferred to be `promise<string>`.
1896+Similarly, `await getUserName(userId)` returns a `string` when the function returns `promise<string>`.
1897+Using `await` outside of an `async` function (including in a non-async callback to an async function) is an error.
1898+
1899+### Ergonomic error handling
1900+
1901+Error handling is done by simply using `try`/`catch`, or a switch with an `exception` case, just as in functions that are not async.
1902+Both JS exceptions and exceptions defined in ReScript can be caught. The compiler takes care of packaging JS exceptions into the builtin `JsError` exception:
1903+
1904+
1905+
1906+## The ignore() Function
1907+
1908+Occasionally you may want to ignore the return value of a function. ReScript provides an `ignore()` function that discards the value of its argument and returns `()`:
1909+
1910+
1911+
1912+## Tips & Tricks
1913+
1914+Cheat sheet for the function syntaxes:
1915+
1916+### Declaration
1917+
1918+
1919+
1920+#### With Type Annotation
1921+
1922+
1923+
1924+### Application
1925+
1926+
1927+
1928+#### With Type Annotation
1929+
1930+
1931+
1932+### Standalone Type Signature
1933+
1934+
1935+
1936+#### In Interface Files
1937+
1938+To annotate a function from the implementation file (`.res`) in your interface file (`.resi`):
1939+
1940+
1941+
1942+The type annotation syntax is the same as described in [With Type Annotation](#with-type-annotation) above.
1943+
1944+**Don't** confuse `let add: myType` with `type add = myType`. When used in `.resi` interface files, the former exports the binding `add` while annotating it as type `myType`. The latter exports the type `add`, whose value is the type `myType`.
1945+# Generalized Algebraic Data Types
1946+
1947+Generalized Algebraic Data Types (GADTs) are an advanced feature of ReScript's type system. "Generalized" can be somewhat of a misnomer -- what they actually allow you to do is add some extra type-specificity to your variants. Using a GADT, you can give the individual cases of a variant _different_ types.
1948+
1949+For a quick overview of the use cases, reach for GADTs when:
1950+
1951+1. You need to distinguish between different members of a variant at the type level.
1952+2. You want to "hide" type information in a type-safe way, without resorting to casts.
1953+3. You need a function to return a different type depending on its input.
1954+
1955+GADTs usually are overkill, but when you need them, you need them! Understanding them from first principles is difficult, so it is best to explain through some motivating examples.
1956+
1957+## Distinguishing Constructors (Subtyping)
1958+
1959+Suppose a simple variant type that represents the current timezone of a date value. This handles both daylight savings and standard time:
1960+
1961+
1962+
1963+Using this variant type, we will end up having functions like this:
1964+
1965+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
1966+
1967+
1968+
1969+This function is only valid for a subset of our variant type's constructors but we can't handle this in a type-safe way using regular variants. We have to enforce that at runtime -- and moreover the compiler can't help us ensure we are failing only in the invalid cases. We are back to dynamically checking validity like we would in a language without static typing. If you work with a large variant type long enough, you will frequently find yourself writing repetitive catchall `switch` statements like the above, and for little actual benefit. The compiler should be able to help us here.
1970+
1971+Let's see if we can find a way for the compiler to help us with normal variants. We could define another variant type to distinguish the two kinds of timezone.
1972+
1973+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
1974+
1975+
1976+
1977+This has a lot of problems. For one, it's cumbersome and redundant. We would now have to pattern-match twice whenever we deal with a timezone that's wrapped up here. The compiler will force us to check whether we are dealing with daylight or standard time, but notice that there's nothing stopping us from providing invalid timezones to these constructors:
1978+
1979+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
1980+
1981+
1982+
1983+Consequently, we still have to write our redundant catchall cases. We could define daylight savings time and standard time as two _separate_ types, and unify those in our `daylightOrStandard` variant.
1984+That could be a passable solution, but what we would really like to do is implement some kind of subtyping relationship.
1985+We have two _kinds_ of timezone. This is where GADTs are handy:
1986+
1987+
1988+
1989+We define our type with a type parameter. We manually annotate each constructor, providing it with the correct type parameter indicating whether it is standard or daylight. Each constructor is a `timezone`,
1990+but we've added another level of specificity using a type parameter. Constructors are now understood to be `standard` or `daylight` at the _type_ level. Now we can fix our function like this:
1991+
1992+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
1993+
1994+
1995+
1996+The compiler can infer correctly that this function should only take `timezone<standard>` and only output
1997+`timezone<daylight>`. We don't need to add any redundant catchall cases and the compiler will even error if
1998+we try to return a standard timezone from this function. Actually, this seems like it could be a problem,
1999+we still want to be able to match on all cases of the variant sometimes, and a naive attempt at this will not pass the type checker. A naive example will fail:
2000+
2001+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
2002+
2003+
2004+
2005+This will complain that `daylight` and `standard` are incompatible. To fix this, we need to explicitly annotate to tell the compiler to accept both:
2006+
2007+{/* TODO: fix this example, it has an error because it doesn't have access to the previous snippet */}
2008+
2009+
2010+
2011+The syntax `type a.` here defines a _locally abstract type_ which basically tells the compiler that the type parameter a is some specific type, but we don't care what it is. The cost of the extra specificity and safety that
2012+GADTs give us is that the compiler less able to help us with type inference.
2013+
2014+## Varying return type
2015+
2016+Sometimes, a function should have a different return type based on what you give it, and GADTs are how we can do this in a type-safe way. We can implement a generic `add` function that works on both `int` or `float`:
2017+
2018+{/* this example purposefully has an error so it is not marked as an example */}
2019+
2020+
2021+
2022+How does this work? The key thing is the function signature for add. The `number` GADT is acting as a _type witness_. We have told the compiler that the type parameter for `number` will be the same as the type we return -- both are set to `a`. So if we provide a `number<int>`, `a` equals `int`, and the function will therefore return an `int`.
2023+
2024+We can also use this to avoid returning `option` unnecessarily. We create an array searching function which either raises an exception, returns an `option`, or provides a `default` value depending on the behavior we ask for.[^2]
2025+
2026+[^2]: This example is adapted from [here](https://dev.realworldocaml.org/gadts.html).
2027+
2028+
2029+
2030+## Hide and recover Type information Dynamically
2031+
2032+In an advanced case that combines the above techniques, we can use GADTs to selectively hide and recover type information. This helps us create more generic types.
2033+The below example defines a `num` type similar to our above addition example, but this lets us use `int` and `float` arrays
2034+interchangeably, hiding the implementation type rather than exposing it. This is similar to a regular variant. However, it is a tuple including embedding a `numTy` and another value.
2035+`numTy` serves as a type-witness, making it
2036+possible to recover type information that was hidden dynamically. Matching on `numTy` will "reveal" the type of the other value in the pair. We can use this to write a generic sum function over arrays of numbers:
2037+
2038+
2039+
2040+## A Practical Example -- writing bindings:
2041+
2042+Javascript libraries that are highly polymorphic or use inheritance can benefit hugely from GADTs, but they can be useful for bindings even in other cases. The following examples are writing bindings to a simplified
2043+of Node's `Stream` API.
2044+
2045+This API has a method for binding event handlers, `on`. This takes an event and a callback. The callback accepts different parameters
2046+depending on which event we are binding to. A naive implementation might look similar to this, defining a
2047+separate method for each stream event to wrap the unsafe version of `on`.
2048+
2049+{/* TODO: fix this example, it has an error */}
2050+
2051+
2052+
2053+Not only is this quite tedious to write and quite ugly, but we gain very little in return. The function wrappers even add performance overhead, so we are losing on all fronts. If we define subtypes of
2054+Stream like `Readable` or `Writable`, which have all sorts of special interactions with the callback that jeopardize our type-safety, we are going to be in even deeper trouble.
2055+
2056+Instead, we can use the same GADT technique that let us vary return type to vary the input type.
2057+Not only are we able to now just use a single method, but the compiler will guarantee we are always using the correct callback type for the given event. We simply define an event GADT which specifies
2058+the type signature of the callback and pass this instead of a plain string.
2059+
2060+Additionally, we use some type parameters to represent the different types of Streams.
2061+
2062+This example is complex, but it enforces tons of useful rules. The wrong event can never be used
2063+with the wrong callback, but it also will never be used with the wrong kind of stream. The compiler will for example complain if we try to use a `Pipe` event with anything other than a `writable` stream.
2064+
2065+The real magic happens in the signature of `on`. Read it carefully, and then look at the examples and try to
2066+follow how the type variables are getting filled in, write it out on paper what each type variable is equal
2067+to if you need and it will soon become clear.
2068+
2069+{/* TODO: fix this example, it has an error */}
2070+
2071+
2072+
2073+This example is only over a tiny, imaginary subset of Node's Stream API, but it shows a real-life example
2074+where GADTs are all but indispensable.
2075+
2076+## Conclusion
2077+
2078+While GADTs can make your types extra-expressive and provide more safety, with great power comes great
2079+responsibility. Code that uses GADTs can sometimes be too clever for its own good. The type errors you
2080+encounter will be more difficult to understand, and the compiler sometimes requires extra help to properly
2081+type your code.
2082+
2083+However, there are definite situations where GADTs are the _right_ decision
2084+and will _simplify_ your code and help you avoid bugs, even rendering some bugs impossible. The `Stream` example above is a good example where the "simpler" alternative of using regular variants or even strings
2085+would lead to a much more complex and error prone interface.
2086+
2087+Ordinary variants are not necessarily _simple_ therefore, and neither are GADTs necessarily _complex_.
2088+The choice is rather which tool is the right one for the job. When your logic is complex, the highly expressive nature of GADTs can make it simpler to capture that logic.
2089+When your logic is simple, it's best to reach for a simpler tool and avoid the cognitive overhead.
2090+The only way to get good at identifying which tool to use in a given situation is to practice and experiment with both.
2091+# Generate Converters & Helpers
2092+
2093+**Note**: if you're looking for:
2094+
2095+- `@deriving(jsConverter)` for records
2096+- `@deriving({jsConverter: newType})` for records
2097+- `@deriving(abstract)` for records
2098+- `@deriving(jsConverter)` for plain and polymorphic variants
2099+
2100+These particular ones are no longer needed. Select a doc version lower than `9.0` in the sidebar to see their old docs.
2101+
2102+{/* TODO: genType */}
2103+
2104+When using ReScript, you will sometimes come into situations where you want to
2105+
2106+- Automatically generate functions that convert between ReScript's internal and JS runtime values (e.g. variants).
2107+- Convert a record type into an abstract type with generated creation, accessor and method functions.
2108+- Generate some other helper functions, such as functions from record attribute names.
2109+
2110+You can use the `@deriving` decorator for different code generation scenarios. All different options and configurations will be discussed on this page.
2111+
2112+**Note:** Please be aware that extensive use of code generation might make it harder to understand your programs (since the code being generated is not visible in the source code, and you just need to know what kind of functions / values a decorator generates).
2113+
2114+## Generate Functions & Plain Values for Variants
2115+
2116+Use `@deriving(accessors)` on a variant type to create accessor functions for its constructors.
2117+
2118+
2119+
2120+Variants constructors with payloads generate functions, payload-less constructors generate plain integers (the internal representation of variants).
2121+
2122+**Note**:
2123+
2124+- The generated accessors are lower-cased.
2125+- You can now use these helpers on the JavaScript side! But don't rely on their actual values please.
2126+
2127+### Usage
2128+
2129+
2130+
2131+This is useful:
2132+
2133+- When you're passing the accessor function as a higher-order function (which plain variant constructors aren't).
2134+- When you'd like the JS side to use these values & functions opaquely and pass you back a variant constructor (since JS has no such thing).
2135+
2136+Please note that in case you just want to _pipe a payload into a constructor_, you don't need to generate functions for that. Use the `->` syntax instead, e.g. `"test"->Submit`.
2137+
2138+## Generate Field Accessors for Records
2139+
2140+Use `@deriving(accessors)` on a record type to create accessors for its record field names.
2141+
2142+
2143+# Import & Export
2144+
2145+## Import a Module/File
2146+
2147+Unlike JavaScript, ReScript doesn't have or need import statements:
2148+
2149+
2150+
2151+The above code refers to the `message` binding in the file `Student.res`. Every ReScript file is also a module, so accessing another file's content is the same as accessing another module's content!
2152+
2153+A ReScript project's file names need to be unique.
2154+
2155+## Export Stuff
2156+
2157+By default, every file's type declaration, binding and module is exported, aka publicly usable by another file. **This also means those values, once compiled into JS, are immediately usable by your JS code**.
2158+
2159+To only export a few selected things, use a `.resi` [interface file](./module.mdx#signatures).
2160+
2161+## Work with JavaScript Import & Export
2162+
2163+To see how to import JS modules and export stuff for JS consumption, see the JavaScript Interop section's [Import from/Export to JS](./import-from-export-to-js.mdx).
2164+# Import from/Export to JS
2165+
2166+You've seen how ReScript's idiomatic [Import & Export](./import-export.mdx) works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.
2167+
2168+If you're looking for react-specific interop guidance, check out the [React JS Interop guide](../react/import-export-reactjs.mdx).
2169+
2170+**Tip**: keep your compiled JS output open in a tab to verify the generated import/export code.
2171+
2172+In short: **make sure your bindings below output what you'd have manually written in JS**.
2173+
2174+## Output Format
2175+
2176+We support 2 JavaScript import/export formats:
2177+
2178+- JavaScript module: `import * from 'MyReScriptFile'` and `export let ...`.
2179+- CommonJS: `require('myFile')` and `module.exports = ...`.
2180+
2181+The format is [configurable in via `rescript.json`](./build-configuration.mdx#package-specs).
2182+
2183+## Import From JavaScript
2184+
2185+### Import a JavaScript Module's Named Export
2186+
2187+Use the `module` [external](./external.mdx):
2188+
2189+
2190+
2191+Here's what the `external` does:
2192+
2193+- `@module("path")`: pass the name of the JS module; in this case, `"path"`. The string can be anything: `"./src/myJsFile"`, `"@myNpmNamespace/myLib"`, etc.
2194+- `external`: the general keyword for declaring a value that exists on the JS side.
2195+- `dirname`: the binding name you'll use on the ReScript side.
2196+- `string => string`: the type signature of `dirname`. Mandatory for `external`s.
2197+- `= "dirname"`: the name of the variable inside the `path` JS module. There's repetition in writing the first and second `dirname`, because sometime the binding name you want to use on the ReScript side is different than the variable name the JS module exported.
2198+
2199+### Import a JavaScript Module As a Single Value
2200+
2201+By omitting the string argument to `module`, you bind to the whole JS module:
2202+
2203+
2204+
2205+Depending on whether you're compiling ReScript to JavaScript module or CommonJS, **this feature will generate subtly different code**. Please check both output tabs to see the difference. The JavaScript module output here would be wrong!
2206+
2207+### Import an `default` Export
2208+
2209+Use the value `default` on the right hand side:
2210+
2211+
2212+
2213+### Use Import Attributes
2214+
2215+**Since 11.1**
2216+
2217+[Import attributes](https://github.com/tc39/proposal-import-attributes) can be used in ReScript, as long as ReScript is configured to output JavaScript module. You do that by passing configuration to the `@module` attribute:
2218+
2219+
2220+
2221+This above imports the local `./myJson.json` file, adding import attributes.
2222+
2223+This is how it works:
2224+
2225+1. Instead of passing a string or tuple to `@module`, pass a record.
2226+2. This record should have a `from` key. The value of that is where you want the module to be imported from (just like the regular string to `@module` is).
2227+3. It should also have a `with` key, with another record where you put all the import attributes you want emitted.
2228+
2229+Notice `\"some-exotic-identifier"` - you'll need to escape any key that's not a valid ReScript record key.
2230+Also notice `type_`. Since `type` is a reserved keyword in ReScript, you can use `type_` instead. It will be output as `type` in the JavaScript code.
2231+
2232+## Dynamic Import
2233+
2234+Leveraging JavaScript's [dynamic `import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) to reduce bundle size and lazy load code as needed is easy in ReScript. It's also a little bit more convenient than in regular JavaScript because you don't need to keep track of file paths manually with ReScript's module system.
2235+
2236+### Dynamically Importing Parts of a Module
2237+
2238+Use the `import` function to dynamically import a specific part of a module. Put whatever `let` binding you want to import in there, and you'll get a `promise` back resolving to that specific binding.
2239+
2240+Let's look at an example. Imagine the following file `MathUtils.res`:
2241+
2242+
2243+
2244+Now let's dynamically import the add function in another module, e.g. `App.res`:
2245+
2246+
2247+
2248+### Dynamically Importing an Entire Module
2249+
2250+The syntax for importing a whole module looks a little different, since we are operating on the module syntax level; instead of using `import`, you may simply `await` the module itself:
2251+
2252+
2253+
2254+## Export To JavaScript
2255+
2256+### Export a Named Value
2257+
2258+As mentioned in ReScript's idiomatic [Import & Export](./import-export.mdx), every let binding and module is exported by default to other ReScript modules (unless you use a `.resi` [interface file](./module.mdx#signatures)). If you open up the compiled JS file, you'll see that these values can also directly be used by a _JavaScript_ file too.
2259+
2260+### Export a `default` Value
2261+
2262+If your JS project uses JavaScript module, you're likely exporting & importing some default values:
2263+
2264+
2265+
2266+
2267+
2268+A JavaScript default export is really just syntax sugar for a named export implicitly called `default` (now you know!). So to export a default value from ReScript, you can just do:
2269+
2270+
2271+
2272+You can then import this default export as usual on the JS side:
2273+
2274+
2275+
2276+If your JavaScript's default import is transpiled by Babel/Webpack/Jest into CommonJS `require`s, we've taken care of that too! See the CommonJS output tab for `__esModule`.
2277+# Inlining Constants
2278+
2279+Sometimes, in the JavaScript output, you might want a certain value to be forcefully inlined. For example:
2280+
2281+
2282+
2283+The reason is that your JavaScript bundler (e.g. Webpack) might turn that into:
2284+
2285+
2286+
2287+Then your subsequent Uglifyjs optimization would remove that entire `if` block. This is how projects like ReactJS provide a development mode code with plenty of dev warnings, while ensuring that the uglified (minified) production code is free of those expensive blocks.
2288+
2289+So, in ReScript, producing that example `if (process.env.mode === 'development')` output is important. This first try doesn't work:
2290+
2291+
2292+
2293+The JS output shows `if (process.env.mode === mode)`, which isn't what we wanted. To inline `mode`'s value, use `@inline`:
2294+
2295+
2296+
2297+Now your resulting JS code can pass through Webpack and Uglifyjs like the rest of your JavaScript code, and that whole `console.log` can be removed.
2298+
2299+The inlining currently only works for **string, float and boolean**.
2300+
2301+## Tips & Tricks
2302+
2303+This is **not** an optimization. This is an edge-case feature for folks who absolutely need particular values inlined for a JavaScript post-processing step, like conditional compilation. Beside the difference in code that the conditional compilation might end up outputting, there's no performance difference between inlining and not inlining simple values in the eyes of a JavaScript engine.
2304+# Installation
2305+
2306+## Prerequisites
2307+
2308+<div className="install-list">
2309+- [Node.js](https://nodejs.org/) version >= 22
2310+- One of the following package managers:
2311+ - [npm](https://docs.npmjs.com/cli/) (comes with Node.js)
2312+ - [yarn](https://yarnpkg.com/)
2313+ - yarn versions >1 need to set `nodeLinker: node-modules` in `.yarnrc.yml`
2314+ - [pnpm](https://pnpm.io/)
2315+ - [bun](https://bun.sh/)
2316+ - [deno](http://deno.com/)
2317+ - Configure `"nodeModulesDir": "auto"` in `deno.json`
2318+</div>
2319+
2320+## New Project
2321+
2322+The fastest and easiest way to spin up a new ReScript project is with the [create-rescript-app](https://github.com/rescript-lang/create-rescript-app) project generator. This will get you started with a fresh Next.js or Vite app with React and Tailwind CSS.
2323+
2324+You can start it with any of the aforementioned package managers or `npx`.
2325+
2326+
2327+
2328+- Follow the steps of the setup.
2329+- Trigger a ReScript build:
2330+
2331+
2332+- If you selected the "basic" template, simply run it with:
2333+
2334+
2335+
2336+That compiles your ReScript into JavaScript, then uses Node.js to run said JavaScript.
2337+
2338+**When taking your first steps with ReScript, we recommend you use our unique workflow of keeping a tab open for the generated JS file** (`.res.js`/`.res.mjs`), so that you can learn how ReScript transforms into JavaScript. Not many languages output clean JavaScript code you can inspect and learn from! With our [VS Code extension](https://marketplace.visualstudio.com/items?itemName=chenglou92.rescript-vscode), use the command "ReScript: Open the compiled JS file for this implementation file" to open the generated JS file for the currently active ReScript source file.
2339+
2340+During development, instead of running `npm run res:build` each time to compile, use `npm run res:dev` to start a watcher that recompiles automatically after file changes.
2341+
2342+## Integrate Into an Existing JS Project
2343+
2344+If you already have a JavaScript project into which you'd like to add ReScript you can do that in the following ways:
2345+
2346+### Quick Setup
2347+
2348+In the root directory of your project, execute:
2349+
2350+
2351+
2352+`create-rescript-app` will tell you that a `package.json` file has been detected and ask you if it should install ReScript into your project. Just follow the steps accordingly.
2353+
2354+### Manual Setup
2355+
2356+- Install ReScript locally:
2357+
2358+
2359+
2360+ <Info>
2361+ **pnpm users:** ReScript-compiled JS imports from `@rescript/runtime` directly, but pnpm's strict isolation does not expose transitive dependencies at the app root. Either install the runtime as a direct dependency (`pnpm add @rescript/runtime`), or hoist it by adding the following to `pnpm-workspace.yaml`:
2362+
2363+
2364+ </Info>
2365+
2366+- Create a ReScript build configuration file (called `rescript.json`) at the root:
2367+
2368+ See [Build Configuration](./build-configuration.mdx) for more details on `rescript.json`.
2369+- Add convenience `npm` scripts to `package.json`:
2370+
2371+
2372+Since ReScript compiles to clean readable JS files, the rest of your existing toolchain (e.g. Vite, Rspack, Rollup) should just work!
2373+
2374+Helpful guides:
2375+
2376+- [Converting from JS](./converting-from-js.mdx).
2377+- [Shared Data Types](./shared-data-types.mdx).
2378+- [Import from/Export to JS](./import-from-export-to-js.mdx).
2379+
2380+### Integrate with a ReactJS Project
2381+
2382+To start a [rescript-react](../react/introduction.mdx) app, or to integrate ReScript into an existing ReactJS app, follow the instructions [here](../react/installation.mdx).
2383+# Interop Cheatsheet
2384+
2385+This is a glossary with examples. All the features are described by later pages.
2386+
2387+## List of Decorators
2388+
2389+> **Note:** In ReScript < 8.3, all our attributes started with the `bs.` prefix. This is no longer needed and our formatter automatically removes them in newer ReScript versions.
2390+
2391+{/* Synced from https://github.com/rescript-lang/syntax/blob/123760c5a264da5288eeee5213ddd25eb86d62fe/src/res_printer.ml#L19-L51 */}
2392+
2393+### Attributes
2394+
2395+- `@as`: [here](./attribute.mdx#usage), [here](./bind-to-js-function.mdx#fixed-arguments), [here](./bind-to-js-function.mdx#constrain-arguments-better) and [here](./generate-converters-accessors.mdx#usage-3)
2396+- [`@deriving`](./generate-converters-accessors.mdx#generate-functions--plain-values-for-variants)
2397+- [`@get`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
2398+- [`@get_index`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
2399+- [`@inline`](./inlining-constants.mdx)
2400+- [`@int`](./bind-to-js-function.mdx#constrain-arguments-better)
2401+- [`@module`](./import-from-export-to-js.mdx#import-a-javascript-modules-content)
2402+- [`@new`](./bind-to-js-object.mdx#bind-to-a-js-object-thats-a-class)
2403+- [`@optional`](./generate-converters-accessors.mdx#optional-labels)
2404+- [`@return`](./bind-to-js-function.mdx#function-nullable-return-value-wrapping)
2405+- `@send`: [here](./bind-to-js-function.mdx#object-method) and [here](./pipe.mdx#js-method-chaining)
2406+- [`@scope`](./bind-to-global-js-values.mdx#global-modules)
2407+- [`@set`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
2408+- [`@set_index`](./bind-to-js-object.mdx#bind-using-special-bs-getters--setters)
2409+- [`@variadic`](./bind-to-js-function.mdx#variadic-function-arguments)
2410+- [`@string`](./bind-to-js-function.mdx#constrain-arguments-better)
2411+- [`@this`](./bind-to-js-function.mdx#modeling-this-based-callbacks)
2412+- [`@uncurry`](./bind-to-js-function.mdx#extra-solution)
2413+- [`@unwrap`](./bind-to-js-function.mdx#trick-2-polymorphic-variant--bsunwrap)
2414+- [`@val`](./bind-to-global-js-values.mdx#global-modules)
2415+- [`@taggedTemplate`](./bind-to-js-function.mdx#tagged_template-functions)
2416+- [`@deprecated`](./attribute.mdx#usage)
2417+- [`genType`](https://github.com/reason-association/genType)
2418+- [`@JSX`](./jsx.mdx)
2419+- `@react.component`: [here](../react/introduction.mdx) and [here](https://github.com/reasonml/reason-react)
2420+- [`@warning`](./attribute.mdx#usage)
2421+- [`@unboxed`](./variant.mdx#untagged-variants)
2422+
2423+### Extension Points
2424+
2425+- [`%debugger`](./embed-raw-javascript.mdx#debugger)
2426+- [`%external`](./bind-to-global-js-values.mdx#special-global-values)
2427+- [`%raw`](./embed-raw-javascript.mdx#paste-raw-js-code)
2428+- [`%todo`](../../syntax-lookup/extension_todo.mdx)
2429+
2430+## Raw JS
2431+
2432+
2433+
2434+## Global Value
2435+
2436+
2437+
2438+## Global Module's Value
2439+
2440+
2441+
2442+## Nullable
2443+
2444+
2445+
2446+Handling a value that can be `undefined` and `null`, by ditching the `option` type and using `Nullable.t`:
2447+
2448+
2449+
2450+## JS Object
2451+
2452+- [Bind to a JS object as a ReScript record](./bind-to-js-object.mdx#bind-to-record-like-js-objects).
2453+- [Bind to a JS object that acts like a hash map](./bind-to-js-object.mdx#bind-to-hash-map-like-js-object).
2454+- [Bind to a JS object that's a class](./bind-to-js-object.mdx#bind-to-a-js-object-thats-a-class).
2455+
2456+## Function
2457+
2458+### Object Method & Chaining
2459+
2460+
2461+
2462+### Variadic Arguments
2463+
2464+
2465+
2466+### Tagged template functions
2467+
2468+
2469+
2470+### Polymorphic Function
2471+
2472+
2473+
2474+
2475+
2476+## JS Module Interop
2477+
2478+[See here](./import-from-export-to-js.mdx)
2479+
2480+## Dangerous Type Cast
2481+
2482+Final escape hatch converter. Do not abuse.
2483+
2484+
2485+# Interop with JS Build Systems
2486+
2487+If you come from JS, chances are that you already have a build system in your existing project. Here's an overview of the role `rescript` would play in your build pipeline, if you want to introduce some ReScript code.
2488+
2489+> **Please** try not to wrap `rescript` into your own incremental build framework. ReScript's compilation is very hard to get right, and you'll inevitably run into stale or badly performing builds (therefore erasing much of our value proposition) if you create your own meta layer on top.
2490+
2491+## Popular JS Build Systems
2492+
2493+The JS ecosystem uses a few build systems: [vite](https://vite.dev/), [browserify](http://browserify.org/), [rollup](https://github.com/rollup/rollup), [webpack](https://webpack.js.org/), etc. The first one is probably the most popular of the four (as of 2025). These build systems do both the compilation and the linking (aka, bundling many files into one or few files).
2494+
2495+`rescript` only takes care of the compilation step; it maps one `.res`/`.resi` file into one JS output file. As such, in theory, no build system integration is needed from our side. From e.g. the webpack watcher's perspective, the JS files ReScript generates are almost equivalent to your hand-written JS files. We also recommend **that you initially check in those ReScript-generated JS files**, as this workflow means:
2496+
2497+- You can introduce ReScript silently into your codebase without disturbing existing infra.
2498+- You have a **visual** diff of the performance & correctness of your JS file when you update the `.res` files and the JS artifacts change.
2499+- You can let teammates hot-patch the JS files in emergency situations, without needing to first start learning ReScript.
2500+- You can remove ReScript completely from your codebase and things will still work (in case your company decides to stop using us for whatever reason).
2501+
2502+For what it's worth, you can also turn `rescript` into an automated step in your build pipeline, e.g. into a Webpack loader; but such approach is error-prone and therefore discouraged.
2503+
2504+### Tips & Tricks
2505+
2506+You can make ReScript JS files look even more idiomatic through the in-source + bs suffix config in `rescript.json`:
2507+
2508+
2509+
2510+This will:
2511+
2512+- Generate the JS files alongside your ReScript source files.
2513+- Use the file extension `.res.js`, so that you can require these files on the JS side through `require('./MyFile.res.js')`, without needing a loader.
2514+
2515+## Use Loaders on ReScript Side
2516+
2517+"What if my build system uses a CSS/png/whatever loader and I'd like to use it in ReScript?"
2518+
2519+Loaders are indeed troublesome; in the meantime, please use e.g. `%raw("require('./myStyles.css')")` at the top of your file. This just uses [`raw`](./embed-raw-javascript.mdx) to compile the snippet into an actual JS require.
2520+
2521+## Getting Project's Dependencies
2522+
2523+`rescript` generates one `MyFile.d` file per `MyFile` source file; you'll find them in `lib/bs`. These are human readable, machine-friendly list of the dependencies of said `MyFile`. You can read into them for your purpose (though mind the IO overhead). Use these files instead of creating your own dependency graph; we did the hard work of tracking the dependencies as best as possible (including inner modules, `open`s, module names overlap, etc).
2524+
2525+## Run Script Per File Built
2526+
2527+See [js-post-build](./build-configuration.mdx#js-post-build). Though please use it sparingly; if you hook up a node.js script after each file built, you'll incur the node startup time per file!
2528+# ReScript
2529+
2530+ReScript is a robustly typed language that compiles to efficient and human-readable JavaScript. It comes with a lightning fast compiler toolchain that scales to any codebase size.
2531+
2532+## JavaScript Interop
2533+
2534+ReScript compiles to clean, readable, and performant JavaScript, directly runnable in browsers and Node. Your existing package managers, bundlers, frameworks, and test runners all work with ReScript.
2535+
2536+Your existing knowledge of web development transfers to ReScript projects.
2537+
2538+If you are coming from JavaScript, start with [ReScript for JavaScript Developers](./rescript-for-javascript-developers.mdx) for a quick syntax guide.
2539+
2540+ReScript code can be [imported into JavaScript code](./import-from-export-to-js.mdx#export-to-javascript), can [generate types for TypeScript](./typescript-integration.mdx), and ReScript can [import code written in JavaScript or TypeScript](./import-from-export-to-js.mdx#import-from-javascript).
2541+
2542+## Type System
2543+
2544+- Is deliberately curated to be a simple subset most folks will have an easier time to use.
2545+- Sound type system. If a type isn't marked as nullable, the value will never be `undefined`. **ReScript code has no null/undefined errors**.
2546+- No configuration needed. The type system behaves the same way in every project.
2547+- Runs extremely fast precisely thanks to its simplicity and curation. It's one of the fastest compiler & build system toolchains for JavaScript development.
2548+- **Doesn't need type annotations**. Annotate as much or as little as you'd like. The types are inferred by the language (and, again, are guaranteed correct).
2549+
2550+## Compiler
2551+
2552+### Compiles to Optimized JavaScript
2553+
2554+ReScript's type system and compiler generate JavaScript that is performant by default, taking advantage of Just-In-Time optimizations (hidden classes, inline caching, avoiding deopts, etc).
2555+
2556+### Tiny JS Output
2557+
2558+A `Hello world` ReScript program generates **20 bytes** of JS code. Additionally, the standard library pieces you require in are only included when needed.
2559+
2560+### Fast Iteration Loop
2561+
2562+ReScript's build time is **one or two orders of magnitude** faster than alternatives. In its watcher mode, the build system usually finishes before you switch screen from the editor to the terminal tab (two digits of milliseconds). A fast iteration cycle reduces the need of keeping one's mental state around longer; this in turn allows one to stay in the flow longer and more often.
2563+
2564+### Readable Output
2565+
2566+ReScript's JS output is very readable. This is especially important while learning, where users might want to understand how the code's compiled, and to audit for bugs.
2567+
2568+This characteristic, combined with a fully-featured JS interop system, allows ReScript code to be inserted into an existing JavaScript codebase almost unnoticed.
2569+
2570+### Preservation of Code Structure
2571+
2572+ReScript maps one source file to one JavaScript output file. This eases the integration of existing tools such as bundlers and test runners. You can even start writing a single file without much change to your build setup. Each file's code structure is approximately preserved, too.
2573+
2574+### High Quality Dead Code Elimination
2575+
2576+The JavaScript ecosystem is very reliant on dependencies. Shipping the final product inevitably drags in a huge amount of code, lots of which the project doesn't actually use. These regions of dead code impact loading, parsing and interpretation speed. ReScript provides powerful dead code elimination at all levels:
2577+
2578+- Function- and module-level code elimination is facilitated by the well-engineered type system and purity analysis.
2579+- At the global level, ReScript generates code that is naturally friendly to dead code elimination done by bundling tools such as [Rollup](https://github.com/rollup/rollup) and [Closure Compiler](https://developers.google.com/closure/compiler/), after its own sophisticated elimination pass.
2580+- The same applies for ReScript's own tiny runtime (which is written in ReScript itself).
2581+# JSON
2582+
2583+## Parse
2584+
2585+Bind to JavaScript's `JSON.parse` and type the return value as the type you're expecting:
2586+
2587+
2588+
2589+Where `data` can be any type you assume the JSON is. As you can see, this compiles to a straightforward `JSON.parse` call. As with regular JS, this is convenient, but has no guarantee that e.g. the data is correctly shaped, or even syntactically valid. Slightly dangerous.
2590+
2591+## Stringify
2592+
2593+Use [`JSON.stringify`](/docs/manual/api/stdlib/json#value-stringify) if your data is of type `JSON.t` or [`JSON.stringifyAny`](/docs/manual/api/stdlib/json#value-stringifyAny) if it is not.
2594+
2595+
2596+
2597+## Import a JSON file
2598+
2599+Use the `@module` attribute to import JSON files directly.
2600+
2601+
2602+
2603+## Advanced
2604+
2605+The generated types are [variants](./variant.mdx), and decoding them requires you to drill down as much
2606+# JSX
2607+
2608+Would you like some HTML syntax in your ReScript? If not, quickly skip over this section and pretend you didn't see anything!
2609+
2610+ReScript supports the JSX syntax, with some slight differences compared to the one in [ReactJS](https://facebook.github.io/react/docs/introducing-jsx.html). ReScript JSX isn't tied to ReactJS; they translate to normal function calls:
2611+
2612+**Note** for [ReScriptReact](../react/introduction.mdx) readers: this isn't what ReScriptReact turns JSX into, in the end. See Usage section for more info.
2613+
2614+## Capitalized
2615+
2616+
2617+
2618+becomes
2619+
2620+
2621+
2622+## Uncapitalized
2623+
2624+
2625+
2626+becomes
2627+
2628+
2629+
2630+## Fragment
2631+
2632+
2633+
2634+becomes
2635+
2636+
2637+
2638+### Children
2639+
2640+
2641+
2642+This is the syntax for passing a list of two items, `child1` and `child2`, to the children position. It transforms to a list containing `child1` and `child2`:
2643+
2644+
2645+
2646+**Note** again that this isn't the transform for ReScriptReact; ReScriptReact turns the final list into an array. But the idea still applies.
2647+
2648+So naturally, `<MyComponent> myChild </MyComponent>` is transformed to `React.jsx(MyComponent.make, {children: myChild})`. I.e. whatever you do, the arguments passed to the children position will be wrapped in a list.
2649+
2650+## Usage
2651+
2652+See [ReScriptReact Elements & JSX](../react/elements-and-jsx.mdx) for an example application of JSX, which transforms the above calls into a ReScriptReact-specific call.
2653+
2654+Here's a JSX tag that shows most of the features.
2655+
2656+
2657+
2658+## Departures From JS JSX
2659+
2660+- Attributes and children don't mandate `{}`, but we show them anyway for ease of learning. Once you format your file, some of them go away and some turn into parentheses.
2661+- Props spread is supported, but there are some restrictions (see below).
2662+- Punning!
2663+- Props and tag names have to follow ReScript's restrictions on identifiers at the exception of hyphens for lowercase tags ([see below](#hyphens-in-tag-names)).
2664+
2665+### Spread Props
2666+
2667+**Since 10.1**
2668+
2669+JSX props spread is supported with type safety.
2670+
2671+
2672+
2673+Multiple spreads are not allowed:
2674+
2675+
2676+
2677+The spread must be at the first position, followed by other props:
2678+
2679+
2680+
2681+### Punning
2682+
2683+"Punning" refers to the syntax shorthand for when a label and a value are the same. For example, in JavaScript, instead of doing `return {name: name}`, you can do `return {name}`.
2684+
2685+JSX supports punning. `<input checked />` is just a shorthand for `<input checked=checked />`. The formatter will help you format to the punned syntax whenever possible. This is convenient in the cases where there are lots of props to pass down:
2686+
2687+
2688+
2689+Consequently, a JSX component can cram in a few more props before reaching for extra libraries solutions that avoids props passing.
2690+
2691+**Note** that this is a departure from ReactJS JSX, which does **not** have punning. ReactJS' `<input checked />` desugars to `<input checked=true />`, in order to conform to DOM's idioms and for backward compatibility.
2692+
2693+### Hyphens in tag names
2694+
2695+**Since 11.1**
2696+
2697+JSX now supports lowercase tags with hyphens in their name. This allows to bind
2698+to web components.
2699+
2700+Note though that props names can't have hyphens, you should use `@as` to bind to
2701+such props in your custom `JsxDOM.domProps` type ([see generic JSX transform](#generic-jsx-transform-jsx-beyond-react-experimental)).
2702+
2703+
2704+
2705+## Generic JSX transform: JSX beyond React (experimental)
2706+
2707+**Since 11.1**
2708+
2709+While ReScript comes with first class support for JSX in React, it's also possible to have ReScript delegate JSX to other frameworks. You do that by configuring a _generic JSX transform_.
2710+
2711+This is what you need to do to use a generic JSX transform:
2712+
2713+1. Make sure you have a ReScript module that [implements the functions and types necessary for the JSX transform](#implementing-a-generic-jsx-transform-module).
2714+2. Configure `rescript.json` to delegated JSX to that module.
2715+
2716+That's it really. We'll expand on each point below.
2717+
2718+### Configuration
2719+
2720+You configure a generic JSX transform by putting any module name in the `module` config of JSX in `rescript.json`. This can be _any valid module name_. Example part from `rescript.json`:
2721+
2722+
2723+
2724+This will now put the `Preact` module in control of the generated JSX calls. The `Preact` module can be defined by anyone - locally in your project, or by a package. As long a it's available in the global scope. The JSX transform will delegate any JSX related code to `Preact`.
2725+
2726+#### What about `@react.component` for components?
2727+
2728+`@react.component` will still be available, and so is a generic `@jsx.component` notation. Both work the same way.
2729+
2730+### Usage Example
2731+
2732+Here's a quick usage example (the actual definition of `Preact.res` comes below):
2733+
2734+First, configure `rescript.json`:
2735+
2736+
2737+
2738+Now you can build Preact components:
2739+
2740+
2741+
2742+And you can use them just like normal with JSX:
2743+
2744+
2745+
2746+#### File level configuration
2747+
2748+You can configure what JSX transform is used at the file level via `@@jsxConfig`, just like before. Like:
2749+
2750+
2751+
2752+This can be convenient if you're mixing different JSX frameworks in the same project.
2753+
2754+### Implementing a generic JSX transform module
2755+
2756+Below is a full list of everything you need in a generic JSX transform module, including code comments to clarify. It's an example implementation of a `Preact` transform, so when doing this for other frameworks you'd of course adapt what you import from, and so on.
2757+
2758+> You can easily copy-paste-and-adapt this to your needs if you're creating bindings to a JSX framework. Most often, all you'll need to change is what the `@module("") external` points to, so the runtime calls point to the correct JS module.
2759+
2760+
2761+
2762+As you can see, most of the things you'll want to implement will be copy paste from the above. But do note that **everything needs to be there unless explicitly noted** or the transform will fail at compile time.
2763+
2764+To enable this, you need to configure the `jsx` `module` in your `rescript.json`:
2765+
2766+
2767+
2768+_value "Preact" is the name of the module that implements the generic JSX transform._
2769+
2770+## Preserve mode
2771+
2772+**Since 12.0**
2773+
2774+JSX Preserve Mode keeps JSX syntax in the compiled JavaScript output instead of transforming it to `JsxRuntime.jsx` calls. This lets bundlers (ESBuild, SWC, Next.js) or React Server Components handle JSX transformation.
2775+
2776+### Configuration
2777+
2778+
2779+
2780+
2781+
2782+Note that the JSX output is functional but not always the most aesthetically pleasing.
2783+# Lazy Value
2784+
2785+If you have some expensive computations you'd like to **defer and cache** subsequently, you can turn them into _lazy_ values:
2786+
2787+
2788+
2789+**Note**: a lazy value is **not** a [shared data type](./shared-data-types.mdx). Don't rely on its runtime representation in your JavaScript code.
2790+
2791+## Execute The Lazy Computation
2792+
2793+To actually run the lazy value's computation, use `Lazy.get` from the standard library `Lazy` module:
2794+
2795+
2796+
2797+The first time `Lazy.get` is called, the expensive computation happens and the result is **cached**. The second time, the cached value is directly used.
2798+
2799+**You can't re-trigger the computation after the first `get` call**. Make sure you only use a lazy value with computations whose results don't change (e.g. an expensive server request whose response is always the same).
2800+
2801+## Exception Handling
2802+
2803+For completeness' sake, our files read example might throw an exception because of `readdirSync`. Here's how you'd handle it:
2804+
2805+
2806+
2807+Though you should probably handle the exception inside the lazy computation itself.
2808+# Let Binding
2809+
2810+A "let binding", in other languages, might be called a "variable declaration". `let` _binds_ values to names. They can be seen and referenced by code that comes _after_ them.
2811+
2812+
2813+
2814+Because these bindings are pure and known up front, the JS output can inline the calculation and emit `20` directly for `newScore`.
2815+
2816+## Block Scope
2817+
2818+Bindings can be scoped through `{}`.
2819+
2820+
2821+
2822+The whole block is pure too, so the generated JS can collapse it to the final string literal.
2823+
2824+The value of the last line of a scope is implicitly returned.
2825+
2826+### Design Decisions
2827+
2828+ReScript's `if`, `while` and functions all use the same block scoping mechanism. The code below works **not** because of some special "if scope"; but simply because it's the same scope syntax and feature you just saw:
2829+
2830+
2831+
2832+## Bindings Are Immutable
2833+
2834+Let bindings are "immutable", aka "cannot change". This helps our type system deduce and optimize much more than other languages (and in turn, help you more).
2835+
2836+## Binding Shadowing
2837+
2838+The above restriction might sound unpractical at first. How would you change a value then? Usually, 2 ways:
2839+
2840+The first is to realize that many times, what you want isn't to mutate a variable's value. For example, this JavaScript pattern:
2841+
2842+
2843+
2844+...is really just to comment on intermediate steps. You didn't need to mutate `result` at all! You could have just written this JS:
2845+
2846+
2847+
2848+In ReScript, this obviously works too:
2849+
2850+
2851+
2852+Additionally, reusing the same let binding name overshadows the previous bindings with the same name. So you can write this too:
2853+
2854+
2855+
2856+(Though for the sake of clarity, we don't recommend this).
2857+
2858+As a matter of fact, even this is valid code:
2859+
2860+
2861+
2862+The binding you refer to is whatever's the closest upward. No mutation here!
2863+If you need _real_ mutation, e.g. passing a value around, have it modified by many pieces of code, we provide a slightly heavier [mutation feature](./mutation.mdx).
2864+
2865+## Private let bindings
2866+
2867+Private let bindings are introduced in the release [7.2](../../blog/archived/bucklescript-release-7-2.mdx).
2868+
2869+In the module system, everything is public by default,
2870+the only way to hide some values is by providing a separate signature to
2871+list public fields and their types:
2872+
2873+
2874+
2875+`%%private` gives you an option to mark private fields directly
2876+
2877+
2878+
2879+`%%private` also applies to file level modules, so in some cases,
2880+users do not need to provide a separate interface file just to hide some particular values.
2881+
2882+Note interface files are still recommended as a general best practice since they give you better
2883+separate compilation units and also they're better for documentation.
2884+
2885+Still, `%%private` is useful in the following scenarios:
2886+
2887+- **Code generators.** Some code generators want to hide some values but it is sometimes very hard or time consuming for code generators to synthesize the types for public fields.
2888+
2889+- **Quick prototyping.** During prototyping, we still want to hide some values, but the interface file is not stable yet. `%%private` provides you such convenience.
2890+# Libraries & Publishing
2891+
2892+ReScript libraries are just like JavaScript libraries: published & hosted on [NPM](http://npmjs.com). You can reuse your `npm`, `yarn` and `package.json`-related tools to manage them!
2893+
2894+## Tips & Tricks
2895+
2896+### Publish
2897+
2898+We recommend you to check in your compiled JavaScript output, for its [various benefits](./interop-with-js-build-systems.mdx#popular-js-build-systems). If not, then at least consider publishing the JavaScript output by un-ignoring them in your [npmignore](https://docs.npmjs.com/cli/v7/using-npm/developers#keeping-files-out-of-your-package). This way, your published ReScript package comes with plain JavaScript files that JS users can consume. If your project's good, JS users might not even realize that they've installed a library written in ReScript!
2899+
2900+### Find Libraries
2901+
2902+Search `rescript`-related packages on NPM, or use our [Package Index](/packages).
2903+
2904+If you can't find what you're looking for, remember that **you don't need a wrapper** to use a JS library:
2905+
2906+- Most JS data types, such as array and objects, [map over cleanly to ReScript and vice-versa](./shared-data-types.mdx).
2907+- You also have access to the familiar [Core API](/docs/manual/api/stdlib).
2908+- You can use a JavaScript library without needing to install dedicated binding libraries. Check the [`external`](./external.mdx) page.
2909+# Documentation for LLMs
2910+
2911+We adhere to the [llms.txt convention](https://llmstxt.org/) to make documentation accessible to large language models and their applications.
2912+
2913+Currently, we have the following files...
2914+
2915+- [/llms/manual/llms.txt](/llms/manual/llms.txt) — a list of the available files for ReScript language.
2916+- [/llms/manual/llm-full.txt](/llms/manual/llm-full.txt) — complete documentation for ReScript language.
2917+- [/llms/manual/llm-small.txt](/llms/manual/llm-small.txt) — compressed version of the former, without examples.
2918+
2919+...and package-level documentation:
2920+
2921+- [/docs/react/llms](../react/llms.mdx) — the LLms documentation for ReScript React.
2922+
2923+## Notes
2924+
2925+- The content is automatically generated from the same source as the official documentation for the specific version
2926+# Migrate to ReScript 11
2927+
2928+## Foreword
2929+
2930+The ReScript community is proud to introduce ReScript V11 which comes with a ton of new features but also removes a lot of bulk.
2931+A migration to it can be very straightforward, but it can also take some time, depending on your code style or what dependencies you use.
2932+
2933+Please have a look at the full [set of breaking changes](#list-of-all-breaking-changes) below to be able to decide whether this is a task you want to undertake. There is also the possibilty to [opt-out of uncurried mode](#minimal-migration) for now, which is probably the most fundamental change of this release. That and other new and notable features are discussed in the following blogposts:
2934+
2935+- [Blog: Improving Interop with unboxed types](../../blog/improving-interop.mdx)
2936+- [Blog: Enhanced Ergonomics for Record Types](../../blog/enhanced-ergonomics-for-record-types.mdx)
2937+- [Blog: First-Class Dynamic `import()` Support](../../blog/first-class-dynamic-import-support.mdx)
2938+- [Blog: Uncurried Mode by Default](../../blog/uncurried-mode.mdx)
2939+
2940+## Recommended Migration
2941+
2942+### Uncurried Mode
2943+
2944+For uncurried mode to take effect in ReScript 11 there is nothing to configure, it is activated by default.
2945+
2946+### Adapt suffix
2947+
2948+ReScript 11 now allows having arbitrary suffixes in the generated JavaScript files. However, it is still recommended to stick to using `.res.js`, `.res.mjs` or `.res.cjs`. For more information, read the Build System Configuration about [suffixes](./build-configuration.mdx#suffix).
2949+
2950+### rescript.json
2951+
2952+The old configuration filename `bsconfig.json` is deprecated. Rename `bsconfig.json` to `rescript.json` to get rid of the deprecation warning.
2953+
2954+### ReScript Core standard library
2955+
2956+[ReScript Core](https://github.com/rescript-association/rescript-core) is ReScript's new standard library. It replaces the complete `Js` module as well as some of the more frequently used modules from `Belt` and is recommended to use with uncurried mode.
2957+
2958+It will be integrated into the compiler in a future version. In ReScript 11, it still needs to be installed manually:
2959+
2960+
2961+
2962+Then add `@rescript/core` to your `rescript.json`'s dependencies:
2963+
2964+
2965+
2966+Open it so it's available in the global scope.
2967+
2968+
2969+
2970+One major change to be aware of is that array access now returns an `option`.
2971+
2972+
2973+
2974+If you would like to not use an `option`, you can use [`Array.getUnsafe`](/docs/manual/api/stdlib/array#value-getUnsafe).
2975+
2976+For a detailed explanation on migration to ReScript Core, please refer to its [migration guide](https://github.com/rescript-association/rescript-core#migration). A semi-automated script is available as well.
2977+
2978+See ReScript Core API docs [here](/docs/manual/api/stdlib).
2979+
2980+### Removed bindings
2981+
2982+Many Node bindings have been removed from the compiler. Please use [rescript-nodejs](https://github.com/TheSpyder/rescript-nodejs) instead or write your own local bindings.
2983+
2984+## Minimal Migration
2985+
2986+This guide describes the things to do at least to migrate to ReScript 11.
2987+
2988+### Disable uncurried mode
2989+
2990+If you use currying extensively and don't want to bother with adapting your code, or have dependencies that just don't work with uncurried mode yet, just set it to false in your `rescript.json`.
2991+
2992+
2993+
2994+For more information, read the Build System Configuration about [uncurried](./build-configuration.mdx#uncurried).
2995+
2996+## List of all breaking changes
2997+
2998+Below is an excerpt from the compiler changelog about all the breaking changes of ReScript 11.
2999+
3000+### Language and Compiler
3001+
3002+- Add smart printer for pipe chains. https://github.com/rescript-lang/rescript-compiler/pull/6411 (the formatter will reformat existing code in certain cases)
3003+- Parse `assert` as a regular function. `assert` is no longer a unary expression. Example: before `assert 1 == 2` is parsed as `(assert 1) == 2`, now it is parsed as `assert(1 == 2)`. https://github.com/rescript-lang/rescript-compiler/pull/6180
3004+- Remove support for the legacy Reason syntax. Existing Reason code can be converted to ReScript syntax using ReScript 9 as follows:
3005+ - `npx rescript@9 convert <reason files>`
3006+- Curried after uncurried is not fused anymore: `(. x) => y => 3` is not equivalent to `(. x, y) => 3` anymore. It's instead equivalent to `(. x) => { y => 3 }`.
3007+ Also, `(. int) => string => bool` is not equivalen to `(. int, string) => bool` anymore.
3008+ These are only breaking changes for unformatted code.
3009+- Exponentiation operator `**` is now right-associative. `2. ** 3. ** 2.` now compile to `Math.pow(2, Math.pow(3, 2))` and not anymore `Math.pow(Math.pow(2, 3), 2)`. Parentheses can be used to change precedence.
3010+- Stop mangling object field names. If you had objects with field names containing "\_\_" or leading "\_", they won't be mangled in the compiled JavaScript and represented as it is without changes. https://github.com/rescript-lang/rescript-compiler/pull/6354
3011+- `$$default` is no longer exported from the generated JavaScript when using default exports. https://github.com/rescript-lang/rescript-compiler/pull/6328
3012+- `-bs-super-errors` flag has been deprecated along with Super_errors. https://github.com/rescript-lang/rescript-compiler/pull/6243
3013+- Remove unsafe `` j`$(a)$(b)` `` interpolation deprecated in compiler version 10 https://github.com/rescript-lang/rescript-compiler/pull/6068
3014+- `@deriving(jsConverter)` not supported anymore for variant types https://github.com/rescript-lang/rescript-compiler/pull/6088
3015+- New representation for variants, where the tag is a string instead of a number. https://github.com/rescript-lang/rescript-compiler/pull/6088
3016+
3017+### Compiler Libraries
3018+
3019+- Fixed name collision between the newly defined Js.Json.t and the variant constructor in the existing Js.Json.kind type. To address this, the usage of the existing Js.Json.kind type can be updated to Js.Json.Kind.t. https://github.com/rescript-lang/rescript-compiler/pull/6317
3020+- Remove rudimentary node bindings and undocumented `%node` extension. https://github.com/rescript-lang/rescript-compiler/pull/6285
3021+- `@rescript/react` >= 0.12.0-alpha.2 is now required because of the React.fragment's children type fix. https://github.com/rescript-lang/rescript-compiler/pull/6238
3022+- Remove deprecated module `Printexc`
3023+
3024+### Build System and Tools
3025+
3026+- Update watcher rules to recompile only on config and `*.res`/`*.resi`/`*.ml`/`.mli` file changes. Solves the issue of unnecessary recompiles on `.css`, `.ts`, and other unrelated file changes. https://github.com/rescript-lang/rescript-compiler/pull/6420
3027+- Made pinned dependencies transitive: if _a_ is a pinned dependency of _b_ and _b_ is a pinned dependency of _c_, then _a_ is implicitly a pinned dependency of _c_. This change is only breaking if your build process assumes non-transitivity.
3028+- Remove obsolete built-in project templates and the "rescript init" functionality. This is replaced by [create-rescript-app](https://github.com/rescript-lang/create-rescript-app) which is maintained separately.
3029+- Do not attempt to build ReScript from source on npm postinstall for platforms without prebuilt binaries anymore.
3030+- GenType: removed support for `@genType.as` for records and variants which has become unnecessary. Use the language's `@as` instead to channge the runtime representation without requiring any runtime conversion during FFI. https://github.com/rescript-lang/rescript-compiler/pull/6099 https://github.com/rescript-lang/rescript-compiler/pull/6101
3031+# Migrate to ReScript 12
3032+
3033+If you encounter any missing information or issues during migration, please [open an issue](https://github.com/rescript-lang/rescript-lang.org/issues/new?template=documentation_issue.md) or, even better, [send a pull request](https://github.com/rescript-lang/rescript-lang.org/) to help improve this guide.
3034+
3035+## Recommended Migration
3036+
3037+### Prerequisites
3038+
3039+- ReScript V11 project.
3040+- Uncurried mode must be enabled (i.e. you have not opted-out from it).
3041+- Your project must not contain any OCaml source code anymore, as support for `.ml` files is removed in this version. However there are ways to convert OCaml syntax with an older ReScript compiler version ([see below](#converting-generated-ml-files)).
3042+- Minimum supported Node.js version is 20.11.0.
3043+
3044+### Standard Library Changes
3045+
3046+In V12, the new standard library ships with the compiler, so you can uninstall and remove the `@rescript/core` dependency from your `rescript.json`
3047+
3048+
3049+
3050+
3051+
3052+Also remove auto opening of `RescriptCore`.
3053+
3054+
3055+
3056+if you had `@rescript/std` installed, remove it as well:
3057+
3058+
3059+
3060+this is replaced by `@rescript/runtime`, which is installed as a dependency of `rescript` now.
3061+
3062+<Info>
3063+ **pnpm users:** since pnpm does not hoist transitive dependencies, you may need to install `@rescript/runtime` as a direct dependency (`pnpm add @rescript/runtime`), or hoist it by adding the following to `pnpm-workspace.yaml`:
3064+
3065+
3066+
3067+</Info>
3068+
3069+## Replacements
3070+
3071+Some typical name changes include:
3072+
3073+- `Error.t` -> `JsError.t`
3074+- `raise(MyException("error"))` -> `throw(MyException("error"))`
3075+- `Js.Exn.Error` exception -> `JsExn`
3076+- `Error.make` -> `JsExn.make`
3077+- `Error.raise` -> `JsExn.raise`
3078+- `Error.message` -> `JsExn.message`
3079+- `Bool.fromStringExn("true")` -> `Bool.fromStringOrThrow("true")`
3080+- `Int.Bitwise.lsl` -> `Int.shiftLeft`
3081+
3082+Tip: You can use the migration tool to automatically replace these with the new functions.
3083+
3084+
3085+
3086+### Bitwise operations
3087+
3088+v11:
3089+
3090+
3091+
3092+v12:
3093+
3094+
3095+
3096+### Shift operations
3097+
3098+v11:
3099+
3100+
3101+
3102+v12:
3103+
3104+
3105+
3106+### JSX children spread
3107+
3108+v11:
3109+
3110+
3111+
3112+v12:
3113+
3114+
3115+
3116+### Attributes
3117+
3118+v11:
3119+
3120+
3121+
3122+v12:
3123+
3124+
3125+
3126+- `@meth` and `@bs.send.pipe` are removed.
3127+
3128+### Assert
3129+
3130+v11:
3131+
3132+
3133+
3134+v12:
3135+
3136+
3137+
3138+## Configuration
3139+
3140+Rename `bsconfig.json` to `rescript.json` and update these configuration options:
3141+
3142+- `bs-dependencies` → `dependencies`
3143+- `bs-dev-dependencies` → `dev-dependencies`
3144+- `bsc-flags` → `compiler-flags`
3145+
3146+### jsx
3147+
3148+- Set `version` to `4` (lower versions are not supported)
3149+- Remove `mode` option (automatically set to `automatic`)
3150+
3151+## Build System Changes
3152+
3153+The build system has been completely rewritten in v12.0.0.
3154+
3155+In v11, we had:
3156+
3157+
3158+
3159+in v12, this becomes:
3160+
3161+
3162+
3163+## Converting generated `.ml` files
3164+
3165+**Note**: This setup is an escape hatch. It keeps legacy generators like `atdgen` working but it also forces you to maintain two compiler versions. Whenever possible migrate such things to modern ReScript tooling such as [Sury](https://github.com/DZakh/sury/).
3166+
3167+Some projects still rely on tools such as `atdgen` that emit `.ml` files. ReScript 12 cannot compile those files directly, so you must keep using ReScript 11 **only** to convert the generated `.ml` files back to `.res` files before you run the v12 build.
3168+
3169+1. Keep ReScript 12 as the sole compiler dependency in your main project (i.e. `devDependencies.rescript` stays at `^12.0.0`).
3170+
3171+2. Install ReScript 11 in a dedicated subfolder (so its binaries never replace the v12 ones in `node_modules/.bin`). A simple option is to store it under a subfolder, e.g. `tools` (if you're using workspaces, keep this folder out of the root workspace list so hoisting can't swap the v12 shims):
3172+
3173+`cd` into `tools` and run `npm create rescript-app` and select the basic template and a v11 version of ReScript. You can name it `rescript-11` for instance.
3174+
3175+3. `cd` back into the root of your project and add a helper script that references the compiler from that folder (adapt the path accordingly):
3176+
3177+
3178+
3179+4. Execute the helper script to convert your `.ml` files to `.res` files:
3180+
3181+
3182+
3183+## List of all breaking changes
3184+
3185+Below is a consolidated excerpt of all the breaking changes from the compiler changelog.
3186+
3187+### Language & syntax
3188+
3189+- Tag functions named `j` or `js` are no longer reserved, so add your own implementation whenever a tagged template expects them. https://github.com/rescript-lang/rescript-compiler/pull/6817
3190+- `lazy` syntax was removed; use the `Lazy` module instead. https://github.com/rescript-lang/rescript-compiler/pull/6342
3191+- All legacy `@bs.*` attributes (e.g. `@bs.as`, `@bs.send`) and `@bs.open` were removed; use their prefix-free successors (`@as`, `@send`, `@open`, …). https://github.com/rescript-lang/rescript-compiler/pull/6643 https://github.com/rescript-lang/rescript-compiler/pull/6629
3192+- `@bs.send.pipe` was removed; rewrite bindings to use `@send`. https://github.com/rescript-lang/rescript-compiler/pull/6858 https://github.com/rescript-lang/rescript-compiler/pull/6891
3193+- OCaml `.ml` files are no longer supported anywhere: `.ml` parsing/formatting went away and the `rescript convert` CLI was removed, so convert legacy files to `.res` before upgrading. https://github.com/rescript-lang/rescript-compiler/pull/6848 https://github.com/rescript-lang/rescript-compiler/pull/6852 https://github.com/rescript-lang/rescript-compiler/pull/6860
3194+- Some global names and old keywords are no longer automatically prefixed during JS emission; update any code that was relying on the mangled names. https://github.com/rescript-lang/rescript-compiler/pull/6831
3195+- JSX v3 and the `-bs-jsx-mode` option were removed and JSX children spreads are no longer valid; JSX v4 semantics are now the only supported mode. https://github.com/rescript-lang/rescript-compiler/pull/7072 https://github.com/rescript-lang/rescript/pull/7327 https://github.com/rescript-lang/rescript/pull/7869
3196+
3197+### Standard library & runtime
3198+
3199+- OCaml compatibility layers in the stdlib and primitives were removed/deprecated. https://github.com/rescript-lang/rescript-compiler/pull/6984
3200+- Deprecated modules `Js.Vector` and `Js.List` were deleted. https://github.com/rescript-lang/rescript-compiler/pull/6900
3201+- The legacy `js_cast.res` helpers were removed; migrate to explicit externals. https://github.com/rescript-lang/rescript-compiler/pull/7075
3202+- `JsError` and related modules were renamed/cleaned up under `JsExn`. https://github.com/rescript-lang/rescript/pull/7408
3203+- `BigInt.fromFloat` now returns `option` and exposes `BigInt.fromFloatOrThrow`, and the `Exn`-suffixed helpers across `Bool`, `BigInt`, `JSON`, `Option`, `Null`, `Nullable`, `Result`, and `List` now end with `OrThrow`. https://github.com/rescript-lang/rescript/pull/7419 https://github.com/rescript-lang/rescript/pull/7518 https://github.com/rescript-lang/rescript/pull/7554
3204+- `Result.getOrThrow` throws a JS `Error` (instead of `Not_found`), and `Result.equal` / `Result.compare` now provide a comparison function for `Error` values. https://github.com/rescript-lang/rescript/pull/7630 https://github.com/rescript-lang/rescript/pull/7933
3205+- `Iterator.forEach` now emits `Iterator.prototype.forEach`. https://github.com/rescript-lang/rescript/pull/7506
3206+- `Date.make` uses `~day` instead of `~date`. https://github.com/rescript-lang/rescript/pull/7324
3207+- Plain `int` multiplication is implemented as a regular int32 operation instead of `Math.imul`. https://github.com/rescript-lang/rescript/pull/7358
3208+- The `List` API was cleaned up—several functions were renamed or removed (see the PR for the exact surface). https://github.com/rescript-lang/rescript/pull/7290
3209+- `String.getSymbol` / `String.setSymbol` were removed; only `String.getSymbolUnsafe` remains on strings. https://github.com/rescript-lang/rescript/pull/7571 https://github.com/rescript-lang/rescript/pull/7626
3210+- `String.charCodeAt` now returns `option<int>` and exposes `String.charCodeAtUnsafe` for unchecked access. https://github.com/rescript-lang/rescript/pull/7877
3211+- `Intl.*.supportedLocalesOf` bindings now return `array<string>` and the non-portable `Intl.PluralRules.selectBigInt` / `selectRangeBigInt` were removed. https://github.com/rescript-lang/rescript/pull/7995
3212+
3213+### Build system & CLI
3214+
3215+- The new Rust-based `rewatch` build system now powers the `rescript` command. The old Ninja-based builder system moved behind `rescript legacy`, and `--compiler-args` became the `compiler-args` subcommand. https://github.com/rescript-lang/rescript/pull/7551 https://github.com/rescript-lang/rescript/pull/7593 https://github.com/rescript-lang/rescript/pull/7928
3216+- `rescript format` was reimplemented in Rust, its options now use the `--check` / `--stdin` long-form spelling, and the `--all` flag was removed because every tracked file (non-dev by default) is formatted automatically. https://github.com/rescript-lang/rescript/pull/7603 https://github.com/rescript-lang/rescript/pull/7752
3217+- The `rescript dump` command was removed; call `bsc` directly if you need to inspect `.cmi` files. https://github.com/rescript-lang/rescript/pull/7710
3218+
3219+### Configuration & platform
3220+
3221+- The minimum supported Node.js version is now 20.11.0. https://github.com/rescript-lang/rescript/pull/7354
3222+- The `experimental-features` key in `rescript.json` now uses kebab-case to match the other config fields. https://github.com/rescript-lang/rescript/pull/7891
3223+- The legacy `-bs-super-errors` flag was removed. https://github.com/rescript-lang/rescript-compiler/pull/6814
3224+# Module Functions
3225+
3226+Module functions can be used to create modules based on types, values, or functions from other modules.
3227+This is a powerful tool that can be used to create abstractions and reusable code that might not be possible with functions, or might have a runtime cost if done with functions.
3228+
3229+This is an advanced part of ReScript and you can generally get by with normal values and functions.
3230+
3231+## Quick example
3232+
3233+Next.js has a `useParams` hook that returns an unknown type,
3234+and it's up to the developer in TypeScript to add a type annotation for the parameters returned by the hook.
3235+
3236+
3237+
3238+In ReScript we can create a module function that will return a typed response for the `useParams` hook.
3239+
3240+
3241+
3242+Now the `PersonData` module has the functions from the `MakeDataModule`.
3243+
3244+
3245+
3246+## Dependency injection
3247+
3248+Module functions can be used for dependency injection.
3249+Here's an example of injecting in some config values into a set of functions to access a database.
3250+
3251+
3252+# Module
3253+
3254+## Basics
3255+
3256+**Modules are like mini files**! They can contain type definitions, `let`
3257+bindings, nested modules, etc.
3258+
3259+### Creation
3260+
3261+To create a module, use the `module` keyword. The module name must start with a
3262+**capital letter**. Whatever you could place in a `.res` file, you may place
3263+inside a module definition's `{}` block.
3264+
3265+
3266+
3267+A module's contents (including types!) can be accessed much like a record's,
3268+using the `.` notation. This demonstrates modules' utility for namespacing.
3269+
3270+
3271+
3272+Nested modules work too.
3273+
3274+
3275+
3276+### `open`ing a module
3277+
3278+Constantly referring to a value/type in a module can be tedious. Instead, we can "open" a module and refer to its contents without always prepending them with the
3279+module's name. Instead of writing:
3280+
3281+
3282+
3283+We can write:
3284+
3285+
3286+
3287+The content of `School` module are made visible (**not** copied into the file, but simply made visible!) in scope. `profession`, `getProfession` and `person1` will thus correctly be found.
3288+
3289+**Use `open` this sparingly, it's convenient, but makes it hard to know where some values come from**. You should usually use `open` in a local scope:
3290+
3291+
3292+
3293+### Use `open!` to ignore shadow warnings
3294+
3295+There are situations where `open` will cause a warning due to existing identifiers (bindings, types) being redefined. Use `open!` to explicitly tell the compiler that this is desired behavior.
3296+
3297+
3298+
3299+**Note:** Same as with `open`, don't overuse `open!` statements if not necessary. Use (sub)modules to prevent shadowing issues.
3300+
3301+### Destructuring modules
3302+
3303+**Since 9.0.2**
3304+
3305+As an alternative to `open`ing a module, you can also destructure a module's functions and values into separate let bindings (similarly on how we'd destructure an object in JavaScript).
3306+
3307+
3308+
3309+**Note:** You can't extract types with module destructuring — use a type alias instead (`type user = User.myUserType`).
3310+
3311+### Extending modules
3312+
3313+Using `include` in a module statically "spreads" a module's content into a new one, thus often fulfill the role of "inheritance" or "mixin".
3314+
3315+**Note**: this is equivalent to a compiler-level copy paste. **We heavily discourage `include`**. Use it as last resort!
3316+
3317+
3318+
3319+**Note**: `open` and `include` are very different! The former brings a module's content into your current scope, so that you don't have to refer to a value by prefixing it with the module's name every time. The latter **copies over** the definition of a module statically, then also do an `open`.
3320+
3321+### Every `.res` file is a module
3322+
3323+Every ReScript file is itself compiled to a module of the same name as the file name, capitalized. The file `React.res` implicitly forms a module `React`, which can be seen by other source files.
3324+
3325+**Note**: ReScript file names should, by convention, be capitalized so that their casing matches their module name. Uncapitalized file names are not invalid, but will be implicitly transformed into a capitalized module name. I.e. `file.res` will be compiled into the module `File`. To simplify and minimize the disconnect here, the convention is therefore to capitalize file names.
3326+
3327+## Signatures
3328+
3329+A module's type is called a "signature", and can be written explicitly. If a
3330+module is like a `.res` (implementation) file, then a module's signature is like
3331+a `.resi` (interface) file.
3332+
3333+### Creation
3334+
3335+To create a signature, use the `module type` keyword. The signature name must start with a
3336+**capital letter**. Whatever you could place in a `.resi` file, you may place
3337+inside a signature definition's `{}` block.
3338+
3339+
3340+
3341+A signature defines the list of requirements that a module must satisfy in order
3342+for that module to match the signature. Those requirements are of the form:
3343+
3344+- `let x: int` requires a `let` binding named `x`, of type `int`.
3345+- `type t = someType` requires a type field `t` to be equal to `someType`.
3346+- `type t` requires a type field `t`, but without imposing any requirements on the actual, concrete type of `t`. We'd use `t` in other entries in the signature to describe relationships, e.g. `let makePair: t => (t, t)` but we cannot, for example, assume that `t` is an `int`. This gives us great, enforced abstraction abilities.
3347+
3348+To illustrate the various kinds of type entries, consider the above signature
3349+`EstablishmentType` which requires that a module:
3350+
3351+- Declare a type named `profession`.
3352+- Must include a function that takes in a value of the type `profession` and returns a string.
3353+
3354+**Note**:
3355+
3356+Modules of the type `EstablishmentType` can contain more fields than the
3357+signature declares, just like the module `School` defined above (if we
3358+choose to assign it the type `EstablishmentType`. Otherwise, `School` exposes
3359+every field). This effectively makes the `person1` field an enforced
3360+implementation detail! Outsiders can't access it, since it's not present in the
3361+signature; the signature **constrained** what others can access.
3362+
3363+The type `EstablishmentType.profession` is **abstract**: it doesn't have a
3364+concrete type; it's saying "I don't care what the actual type is, but it's used
3365+as input to `getProfession`". This is useful to fit many modules under the same
3366+interface:
3367+
3368+
3369+
3370+It's also useful to hide the underlying type as an implementation detail others
3371+can't rely on. If you ask what the type of `Company.profession` is, instead of
3372+exposing the variant, it'll only tell you "it's `Company.profession`".
3373+
3374+This also means that the compiler can't make assumptions about the type.
3375+In certain cases, when working with abstract types and `option` for example, the compiler doesn't know whether
3376+the abstract type can be the JavaScript value `undefined` or not. This can lead to less optimal code being generated.
3377+For this reason, you can use the `@notUndefined` decorator to tell the compiler that the abstract type can never be `undefined`
3378+(use with caution and see the `@notUndefined` decorator documentation for more details and caveats).
3379+
3380+### Extending module signatures
3381+
3382+Like modules themselves, module signatures can also be extended by other module signatures using `include`. Again, **heavily discouraged**:
3383+
3384+
3385+
3386+**Note**: `BaseComponent` is a module **type**, not an actual module itself!
3387+
3388+If you do not have a defined module type, you can extract it from an actual module
3389+using `include (module type of ActualModuleName)`. For example, we can extend the
3390+`List` module from the standard library, which does not define a module
3391+type.
3392+
3393+
3394+
3395+### Every `.resi` file is a signature
3396+
3397+Similar to how a `React.res` file implicitly defines a module `React`, a file
3398+`React.resi` implicitly defines a signature for `React`. If `React.resi` isn't
3399+provided, the signature of `React.res` defaults to exposing all the fields of the
3400+module. Because they don't contain implementation files, `.resi` files are used
3401+in the ecosystem to also document the public API of their corresponding modules.
3402+
3403+
3404+
3405+
3406+
3407+## Module Functions (functors)
3408+
3409+Modules can be passed to functions! It would be the equivalent of passing a file
3410+as a first-class item. However, modules are at a different "layer" of the
3411+language than other common concepts, so we can't pass them to _regular_
3412+functions. Instead, we pass them to special functions called "functors".
3413+
3414+The syntax for defining and using functors is very much like the syntax
3415+for defining and using regular functions. The primary differences are:
3416+
3417+- Functors use the `module` keyword instead of `let`.
3418+- Functors take modules as arguments and return a module.
3419+- Functors _require_ annotating arguments.
3420+- Functors must start with a capital letter (just like modules/signatures).
3421+
3422+Here's an example `MakeSet` functor, that takes in a module of the type
3423+`Comparable` and returns a new set that can contain such comparable items.
3424+
3425+
3426+
3427+Functors can be applied using function application syntax. In this case, we're
3428+creating a set, whose items are pairs of integers.
3429+
3430+
3431+
3432+### Module functions types
3433+
3434+Like with module types, functor types also act to constrain and hide what we may
3435+assume about functors. The syntax for functor types are consistent with those
3436+for function types, but with types capitalized to represent the signatures of
3437+modules the functor accepts as arguments and return values. In the
3438+previous example, we're exposing the backing type of a set; by giving `MakeSet`
3439+a functor signature, we can hide the underlying data structure!
3440+
3441+
3442+
3443+## Exotic Module Filenames
3444+
3445+**Since 8.3**
3446+
3447+It is possible to use non-conventional characters in your filenames (which is sometimes needed for specific JS frameworks). Here are some examples:
3448+
3449+- `src/Button.ios.res`
3450+- `pages/[id].res`
3451+
3452+Please note that modules with an exotic filename will not be accessible from other ReScript modules and will only produce JavaScript files.
3453+
3454+## Tips & Tricks
3455+
3456+Modules and functors are at a different "layer" of language than the rest (functions, let bindings, data structures, etc.). For example, you can't easily pass them into a tuple or record. Use them judiciously, if ever! Lots of times, just a record or a function is enough.
3457+# Mutation
3458+
3459+ReScript has great traditional imperative & mutative programming capabilities. You should use these features sparingly, but sometimes they allow your code to be more performant and written in a more familiar pattern.
3460+
3461+## Mutate Let-binding
3462+
3463+Let-bindings are immutable, but you can wrap it with a `ref`, exposed as a record with a single mutable field in the standard library:
3464+
3465+
3466+
3467+## Usage
3468+
3469+You can get the actual value of a `ref` box through accessing its `contents` field:
3470+
3471+
3472+
3473+Assign a new value to `myValue` like so:
3474+
3475+
3476+
3477+We provide a syntax sugar for this:
3478+
3479+
3480+
3481+Note that the previous binding `five` stays `5`, since it got the underlying item on the `ref` box, not the `ref` itself.
3482+
3483+**Note**: you might see in the JS output tabs above that `ref` allocates an object. Worry not; local, non-exported `ref`s allocations are optimized away.
3484+
3485+## Tip & Tricks
3486+
3487+Before reaching for `ref`, know that you can achieve lightweight, local "mutations" through [overriding let bindings](./let-binding.mdx#binding-shadowing).
3488+# Null, Undefined and Option
3489+
3490+ReScript itself doesn't have the notion of `null` or `undefined`. This is a _great_ thing, as it wipes out an entire category of bugs. No more `undefined is not a function`, and `cannot access someAttribute of undefined`!
3491+
3492+However, the **concept** of a potentially nonexistent value is still useful, and safely exists in our language.
3493+
3494+We represent the existence and nonexistence of a value by wrapping it with the `option` type. Here's its definition from the standard library:
3495+
3496+
3497+
3498+It means "a value of type option is either None (representing nothing) or that actual value wrapped in a Some".
3499+
3500+**Note** how the `option` type is just a regular [variant](./variant.mdx).
3501+
3502+## Example
3503+
3504+Here's a normal value:
3505+
3506+
3507+
3508+To represent the concept of "maybe null", you'd turn this into an `option` type by wrapping it. For the sake of a more illustrative example, we'll put a condition around it:
3509+
3510+
3511+
3512+Later on, when another piece of code receives such value, it'd be forced to handle both cases through [pattern matching](./pattern-matching-destructuring.mdx):
3513+
3514+
3515+
3516+By turning your ordinary number into an `option` type, and by forcing you to handle the `None` case, the language effectively removed the possibility for you to mishandle, or forget to handle, a conceptual `null` value! **A pure ReScript program doesn't have null errors**.
3517+
3518+## Interoperate with JavaScript `undefined` and `null`
3519+
3520+The `option` type is common enough that we special-case it when compiling to JavaScript:
3521+
3522+
3523+
3524+simply compiles down to `5`, and
3525+
3526+
3527+
3528+compiles to `undefined`! If you've got e.g. a string in JavaScript that you know might be `undefined`, type it as `option<string>` and you're done! Likewise, you can send a `Some(5)` or `None` to the JS side and expect it to be interpreted correctly =)
3529+
3530+### Caveat 1
3531+
3532+Unfortunately, lots of times, your JavaScript value might be _both_ `null` or `undefined`. In that case, you unfortunately can't type such value as e.g. `option<int>`, since our `option` type only checks for `undefined` and not `null` when dealing with a `None`.
3533+
3534+#### Solution: More Sophisticated `undefined` & `null` Interop
3535+
3536+To solve this, we provide access to more elaborate `null` and `undefined` helpers through the [`Nullable`](/docs/manual/api/stdlib/nullable) module. This somewhat works like an `option` type, but is different from it.
3537+
3538+#### Examples
3539+
3540+To create a JS `null`, use the value `Nullable.null`. To create a JS `undefined`, use `Nullable.undefined` (you can naturally use `None` too, but that's not the point here; the `Nullable.*` helpers wouldn't work with it).
3541+
3542+If you're receiving, for example, a JS string that can be `null` and `undefined`, type it as:
3543+
3544+
3545+
3546+To create such a nullable string from our side (presumably to pass it to the JS side, for interop purpose), do:
3547+
3548+
3549+
3550+The `return` part "wraps" a string into a nullable string, to make the type system understand and track the fact that, as you pass this value around, it's not just a string, but a string that can be `null` or `undefined`.
3551+
3552+#### Convert to/from `option`
3553+
3554+`Nullable.fromOption` converts from a `option` to `Nullable.t`. `Nullable.toOption` does the opposite.
3555+# Object
3556+
3557+ReScript objects are like [records](./record.mdx), but:
3558+
3559+- No type declaration needed.
3560+- Structural and more polymorphic, [unlike records](./record.mdx#record-types-are-found-by-field-name).
3561+- Doesn't support updates unless the object comes from the JS side.
3562+- Doesn't support [pattern matching](./pattern-matching-destructuring.mdx).
3563+
3564+{/* TODO: support update man */}
3565+
3566+Although ReScript records compile to clean JavaScript objects, ReScript objects are a better candidate for emulating/binding to JS objects, as you'll see.
3567+
3568+## Type Declaration
3569+
3570+**Optional**, unlike for records. The type of an object is inferred from the value, so you never really need to write down its type definition. Nevertheless, here's its type declaration syntax:
3571+
3572+
3573+
3574+Visually similar to record type's syntax, with the field names quoted.
3575+
3576+{/* TODO: document {.} and {..} */}
3577+
3578+## Creation
3579+
3580+To create a new object:
3581+
3582+
3583+
3584+**Note**: as said above, unlike for record, this `me` value does **not** try to find a conforming type declaration with the field `"age"` and `"name"`; rather, the type of `me` is inferred as `{"age": int, "name": string}`. This is convenient, but also means this code passes type checking without errors:
3585+
3586+
3587+
3588+Since the type checker doesn't try to match `me` with the type `person`. If you ever want to force an object value to be of a predeclared object type, just annotate the value:
3589+
3590+
3591+
3592+Now the type system will error properly.
3593+
3594+## Access
3595+
3596+
3597+
3598+## Update
3599+
3600+Disallowed unless the object is a binding that comes from the JavaScript side. In that case, use `=`
3601+
3602+
3603+
3604+## Combine Types
3605+
3606+You can spread one object type definition into another using `...`:
3607+
3608+
3609+
3610+This only works with object types, not object values!
3611+
3612+## Tips & Tricks
3613+
3614+Since objects don't require type declarations, and since ReScript infers all the types for you, you get to very quickly and easily (and dangerously) bind to any JavaScript API. Check the JS output tab:
3615+
3616+
3617+
3618+The `external` feature and the usage of this trick are also documented in the [external](./external.mdx#tips--tricks) section later. It's an excellent way to start writing some ReScript code without worrying about whether bindings to a particular library exists.
3619+# Language Overview
3620+
3621+A concise reference of ReScript's syntax and core language features.
3622+
3623+If you already know JavaScript and want a quick syntax guide first, see [ReScript for JavaScript Developers](./rescript-for-javascript-developers.mdx).
3624+
3625+## Semicolons
3626+
3627+ReScript does not require semicolons. Line breaks are sufficient to separate statements.
3628+
3629+## Comments
3630+
3631+| Syntax | Purpose |
3632+| -------------------------------- | ---------------------- |
3633+| `// Line comment` | Single-line comment |
3634+| `/* Block comment */` | Multi-line comment |
3635+| `/** Doc comment */` | Documentation comment |
3636+| `/*** Standalone doc comment */` | Standalone doc comment |
3637+
3638+## Variables
3639+
3640+| Syntax | Description |
3641+| ------------------------------------- | ----------------------- |
3642+| `let x = 5` | Immutable binding |
3643+| `let x = ref(5); x := x.contents + 1` | Mutable value via `ref` |
3644+
3645+## Strings
3646+
3647+| Syntax | Description |
3648+| ------------------------- | -------------------- |
3649+| `"Hello world!"` | String literal |
3650+| `"hello " ++ "world"` | String concatenation |
3651+| `` `hello ${message}` `` | String interpolation |
3652+| `` sql`select ${col};` `` | Tagged template |
3653+
3654+Strings must use double quotes (`"`).
3655+
3656+## Booleans
3657+
3658+| Syntax | Description |
3659+| -------------------- | ------------------------------ |
3660+| `true`, `false` | Boolean literals |
3661+| `!` | Logical NOT |
3662+| `\|\|`, `&&` | Logical OR, AND |
3663+| `<=`, `>=`, `<`, `>` | Comparison operators |
3664+| `===`, `!==` | Referential (shallow) equality |
3665+| `==`, `!=` | Structural (deep) equality |
3666+
3667+There is no equality with implicit type casting.
3668+
3669+## Numbers
3670+
3671+| Syntax | Description |
3672+| ------------ | ---------------------------------- |
3673+| `3` | Integer literal |
3674+| `3.1415` | Float literal |
3675+| `3 + 4` | Addition (works for int and float) |
3676+| `2 / 3 * 4` | Division and multiplication |
3677+| `2.0 ** 3.0` | Exponentiation |
3678+| `5 % 3` | Modulo |
3679+
3680+Arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`) work for both `int` and `float`.
3681+
3682+## Records
3683+
3684+Records are typed, immutable-by-default data structures with named fields.
3685+
3686+| Syntax | Description |
3687+| --------------------------------------- | -------------------- |
3688+| `type point = {x: int, mutable y: int}` | Type declaration |
3689+| `{x: 30, y: 20}` | Record creation |
3690+| `point.x` | Field access |
3691+| `point.y = 30` | Mutable field update |
3692+| `{...point, x: 30}` | Immutable update |
3693+
3694+## Arrays
3695+
3696+| Syntax | Description |
3697+| ----------------- | ---------------------- |
3698+| `[1, 2, 3]` | Array literal |
3699+| `myArray[1] = 10` | Mutable element update |
3700+
3701+Arrays are homogeneous. For mixed types, use tuples or [Untagged Variants](./variant.mdx#untagged-variants).
3702+
3703+## Tuples
3704+
3705+| Syntax | Description |
3706+| ------------------- | ------------------- |
3707+| `(1, "Bob", true)` | Tuple literal |
3708+| `let (a, b, c) = t` | Tuple destructuring |
3709+
3710+Tuples are fixed-length, heterogeneous, and immutable.
3711+
3712+## Null & Option
3713+
3714+ReScript has no `null` or `undefined`. The `option` type represents the possible absence of a value:
3715+
3716+| Syntax | Description |
3717+| ------------ | --------------- |
3718+| `None` | No value |
3719+| `Some("hi")` | A present value |
3720+
3721+## Functions
3722+
3723+| Syntax | Description |
3724+| ----------------------------- | -------------------- |
3725+| `arg => retVal` | Anonymous function |
3726+| `let named = (arg) => retVal` | Named function |
3727+| `add(4, add(5, 6))` | Function application |
3728+
3729+## Async / Await
3730+
3731+| Syntax | Description |
3732+| ---------------------------------- | ------------------------------ |
3733+| `async (arg) => {...}` | Async anonymous function |
3734+| `let named = async (arg) => {...}` | Async named function |
3735+| `await somePromise` | Await a promise |
3736+| `async (arg): string => {...}` | Typed async (return type only) |
3737+
3738+## Blocks
3739+
3740+The last expression in a `{}` block is implicitly returned, including in function bodies.
3741+
3742+<table>
3743+ <thead>
3744+ <tr>
3745+ <th>Example</th>
3746+ <th>Description</th>
3747+ </tr>
3748+ </thead>
3749+ <tbody>
3750+ <tr>
3751+ <td>
3752+ ```
3753+ let myFun = (x, y) => {
3754+ let doubleX = x + x
3755+ let doubleY = y + y
3756+ doubleX + doubleY
3757+ }
3758+ ```
3759+ </td>
3760+ <td>Function body with implicit return</td>
3761+ </tr>
3762+ <tr>
3763+ <td>
3764+ ```
3765+ let result = {
3766+ let x = 23
3767+ let y = 34
3768+ x + y
3769+ }
3770+ ```
3771+ </td>
3772+ <td>Block expression bound to a variable</td>
3773+ </tr>
3774+ </tbody>
3775+</table>
3776+
3777+## If-Else
3778+
3779+| Syntax | Description |
3780+| ------------------- | ------------------------------------------------------------------------ |
3781+| `if a {b} else {c}` | Conditional expression |
3782+| `a ? b : c` | Ternary expression |
3783+| `switch` | Pattern matching — [see full docs](./pattern-matching-destructuring.mdx) |
3784+
3785+Conditionals are expressions: `let result = if a {"hello"} else {"bye"}`
3786+
3787+## Destructuring
3788+
3789+| Syntax | Description |
3790+| --------------------------- | ------------------------- |
3791+| `let {a, b} = data` | Record destructuring |
3792+| `let [a, b] = data` | Array destructuring \* |
3793+| `let {a: aa, b: bb} = data` | Destructuring with rename |
3794+
3795+\* The compiler warns if `data` might not be of length 2.
3796+
3797+## Loops
3798+
3799+| Syntax | Description |
3800+| ---------------------------- | --------------- |
3801+| `for i in 0 to 10 {...}` | Ascending loop |
3802+| `for i in 10 downto 0 {...}` | Descending loop |
3803+| `while true {...}` | While loop |
3804+
3805+## JSX
3806+
3807+| Syntax | Description |
3808+| ----------------------------------------- | ---------------------- |
3809+| `<Comp message="hi" onClick={handler} />` | Props |
3810+| `<Comp message />` | Argument punning |
3811+| `<input checked=true />` | Explicit boolean props |
3812+| `<Comp>...children</Comp>` | Children spread |
3813+
3814+## Exceptions
3815+
3816+| Syntax | Description |
3817+| --------------------------------------------- | --------------------- |
3818+| `throw(SomeException(...))` | Raise an exception |
3819+| `try a catch { \| SomeException(err) => ...}` | Catch an exception \* |
3820+
3821+\* There is no `finally` clause.
3822+
3823+## Compilation Output Reference
3824+
3825+A reference showing how common ReScript features compile to JavaScript.
3826+
3827+| Feature | ReScript | JavaScript Output |
3828+| ------------------------- | ------------------------------------ | ------------------------------------------ |
3829+| String | `"Hello"` | `"Hello"` |
3830+| String Interpolation | `` `Hello ${message}` `` | `"Hello " + message` |
3831+| Character (discouraged) | `'x'` | `120` (char code) |
3832+| Integer | `23`, `-23` | `23`, `-23` |
3833+| Float | `23.0`, `-23.0` | `23.0`, `-23.0` |
3834+| Addition | `23 + 1` | `23 + 1` |
3835+| Float Addition | `23.0 + 1.0` | `23.0 + 1.0` |
3836+| Division/Multiply | `2 / 23 * 1` | `2 / 23 * 1` |
3837+| Float Division/Multiply | `2.0 / 23.0 * 1.0` | `2.0 / 23.0 * 1.0` |
3838+| Float Exponentiation | `2.0 ** 3.0` | `2.0 ** 3.0` |
3839+| String Concatenation | `"Hello " ++ "World"` | `"Hello " + "World"` |
3840+| Comparison | `>`, `<`, `>=`, `<=` | `>`, `<`, `>=`, `<=` |
3841+| Boolean operation | `!`, `&&`, `\|\|` | `!`, `&&`, `\|\|` |
3842+| Shallow and deep Equality | `===`, `==` | `===`, `==` |
3843+| List (discouraged) | `list{1, 2, 3}` | `{hd: 1, tl: {hd: 2, tl: {hd: 3, tl: 0}}}` |
3844+| List Prepend | `list{a1, a2, ...oldList}` | `{hd: a1, tl: {hd: a2, tl: theRest}}` |
3845+| Array | `[1, 2, 3]` | `[1, 2, 3]` |
3846+| Record | `type t = {b: int}; let a = {b: 10}` | `var a = {b: 10}` |
3847+| Multiline Comment | `/* Comment here */` | Not in output |
3848+| Single line Comment | `// Comment here` | Not in output |
3849+
3850+_Note that this is a cleaned-up reference table; some examples' JavaScript output may differ slightly in practice._
3851+# Pattern Matching / Destructuring
3852+
3853+One of ReScript's **best** features is our pattern matching. Pattern matching combines 3 brilliant features into one:
3854+
3855+- Destructuring.
3856+- `switch` based on shape of data.
3857+- Exhaustiveness check.
3858+
3859+We'll dive into each aspect below.
3860+
3861+## Destructuring
3862+
3863+Even JavaScript has destructuring, which is "opening up" a data structure to extract the parts we want and assign variable names to them:
3864+
3865+
3866+
3867+Destructuring works with most built-in data structures:
3868+
3869+
3870+
3871+You can also use destructuring anywhere you'd usually put a binding:
3872+
3873+
3874+
3875+For a record, you can rename the field while destructuring:
3876+
3877+
3878+
3879+You _can_ in theory destructure array and list at the top level too:
3880+
3881+
3882+
3883+But the array example is **highly disrecommended** (use tuple instead) and the list example will error on you. They're only there for completeness' sake. As you'll see below, the proper way of using destructuring array and list is using `switch`.
3884+
3885+## `switch` Based on Shape of Data
3886+
3887+While the destructuring aspect of pattern matching is nice, it doesn't really change the way you think about structuring your code. One paradigm-changing way of thinking about your code is to execute some code based on the shape of the data.
3888+
3889+Consider a variant:
3890+
3891+
3892+
3893+We'd like to handle each of the 3 cases differently. For example, print a success message if the value is `GoodResult(...)`, do something else when the value is `NoResult`, etc.
3894+
3895+In other languages, you'd end up with a series of if-elses that are hard to read and error-prone. In ReScript, you can instead use the supercharged `switch` pattern matching facility to destructure the value while calling the right code based on what you destructured:
3896+
3897+
3898+
3899+In this case, `message` will have the value `"Success! Product shipped!"`.
3900+
3901+Suddenly, your if-elses that messily checks some structure of the value got turned into a clean, compiler-verified, linear list of code to execute based on exactly the shape of the value.
3902+
3903+### Complex Examples
3904+
3905+Here's a real-world scenario that'd be a headache to code in other languages. Given this data structure:
3906+
3907+
3908+
3909+Imagine this requirement:
3910+
3911+- Informally greet a person who's a teacher and if his name is Mary or Joe.
3912+- Greet other teachers formally.
3913+- If the person's a student, congratulate him/her score if they passed the semester.
3914+- If the student has a gpa of 0 and is on vacations or sabbatical, display a different message.
3915+- A catch-all message for a student.
3916+
3917+ReScript can do this easily!
3918+
3919+
3920+
3921+**Note** how we've:
3922+
3923+- drilled deep down into the value concisely
3924+- using a **nested pattern check** `"Mary" | "Joe"` and `Vacations | Sabbatical`
3925+- while extracting the `daysLeft` number from the latter case
3926+- and assigned the greeting to the binding `message`.
3927+
3928+Here's another example of pattern matching, this time on an inline tuple.
3929+
3930+
3931+
3932+**Note** how pattern matching on a tuple is equivalent to a 2D table:
3933+
3934+| isBig \ myAnimal | Dog | Cat | Bird |
3935+| ---------------- | --- | --- | ---- |
3936+| true | 1 | 2 | 3 |
3937+| false | 4 | 4 | 5 |
3938+
3939+### Fall-Through Patterns
3940+
3941+The nested pattern check, demonstrated in the earlier `person` example, also works at the top level of a `switch`:
3942+
3943+
3944+
3945+Having multiple cases fall into the same handling can clean up certain types of logic.
3946+
3947+### Ignore Part of a Value
3948+
3949+If you have a value like `Teacher(payload)` where you just want to pattern match on the `Teacher` part and ignore the `payload` completely, you can use the `_` wildcard like this:
3950+
3951+
3952+
3953+`_` also works at the top level of the `switch`, serving as a catch-all condition:
3954+
3955+
3956+
3957+**Do not** abuse a top-level catch-all condition. Instead, prefer writing out all the cases:
3958+
3959+
3960+
3961+Slightly more verbose, but a one-time writing effort. This helps when you add a new variant case e.g. `Quarantined` to the `status` type and need to update the places that pattern match on it. A top-level wildcard here would have accidentally and silently continued working, potentially causing bugs.
3962+
3963+### If Clause
3964+
3965+Sometime, you want to check more than the shape of a value. You want to also run some arbitrary check on it. You might be tempted to write this:
3966+
3967+
3968+
3969+`switch` patterns support a shortcut for the arbitrary `if` check, to keep your pattern linear-looking:
3970+
3971+
3972+
3973+### Match on subtype variants
3974+
3975+You can refine a variant A to variant B using the [variant type spread syntax](./variant.mdx#variant-type-spreads) in pattern matching. This is possible if variant B [is a subtype of](./variant.mdx#coercion) variant A.
3976+
3977+Let's look at an example:
3978+
3979+
3980+
3981+Let's break down what we did:
3982+
3983+- Defined two different variants for pets and for fish
3984+- Wrote a dedicated function per animal type to greet that particular type of animal
3985+- Combined `pets` and `fish` into a main variant for `animals`
3986+- Wrote a function that can greet any animal by _spreading_ each sub variant on its own branch, aliasing that spread to a variable, and passing that variable to the dedicated greet function for that specific type
3987+
3988+Notice how we're able to match on parts of the main variant, as long as the variants are compatible.
3989+
3990+The example above aliases the variant type spread to a variable so we can use it in our branch. But, you can just as easily match without aliasing if you don't care about the value:
3991+
3992+
3993+
3994+Similarily, if you want to get advanced, you can even pull out a single variant constructor. This works with and without aliases. Example:
3995+
3996+
3997+
3998+And, thanks to the rules of subtyping, the `Dog` constructor wouldn't _really_ need to be spread inside of the `pets` variant for this to work:
3999+
4000+
4001+
4002+### Match on Exceptions
4003+
4004+If the function throws an exception (covered later), you can also match on _that_, in addition to the function's normally returned values.
4005+
4006+
4007+
4008+### Match on Array
4009+
4010+
4011+
4012+### Match on List
4013+
4014+Pattern matching on list is similar to array, but with the extra feature of extracting the tail of a list (all elements except the first one):
4015+
4016+
4017+
4018+### Match on Dictionaries
4019+
4020+You can pattern match on dictionaries just like you can on other ReScript data structures.
4021+
4022+When pattern matching on a dictionary it's assumed by default that you're expecting the keys you match on to exist in the dictionary. Example:
4023+
4024+
4025+
4026+However, there are situations where you want to pull out the value of a key as an option. You can do that using the `?` optional syntax in the pattern match:
4027+
4028+
4029+
4030+Notice how in the first case, when not using `?`, we had to supply a catch-all case `_`. That's because the pattern match _expects_ `B` to exist in the first case, for the pattern to match. If `B` doesn't exist, the match falls through to the next branch, and therefore we need to catch it to be exhaustive in our matching.
4031+
4032+However, in the second case, we don't need a catch-all case. That's because the first branch will _always_ match the dictionary - either `B` exists or it doesn't, but it doesn't matter because we're pulling it out as an optional value.
4033+
4034+### Small Pitfall
4035+
4036+**Note**: you can only pass literals (i.e. concrete values) as a pattern, not let-binding names or other things. The following doesn't work as expected:
4037+
4038+
4039+
4040+A first time ReScript user might accidentally write that code, assuming that it's matching on `coordinates` when the second value is of the same value as `centerY`. In reality, this is interpreted as matching on coordinates and assigning the second value of the tuple to the name `centerY`, which isn't what's intended.
4041+
4042+## Exhaustiveness Check
4043+
4044+As if the above features aren't enough, ReScript also provides arguably the most important pattern matching feature: **compile-time check of missing patterns**.
4045+
4046+Let's revisit one of the above examples:
4047+
4048+
4049+
4050+Did you see what we removed? This time, we've omitted the handling of the case where `person1` is `Teacher({name})` when `name` isn't Mary or Joe.
4051+
4052+Failing to handle every scenario of a value likely constitutes the majority of program bugs out there. This happens very often when you refactor a piece of code someone else wrote. Fortunately for ReScript, the compiler will tell you so:
4053+
4054+```
4055+Warning 8: this pattern-matching is not exhaustive.
4056+Here is an example of a value that is not matched:
4057+Some({name: ""})
4058+```
4059+
4060+**BAM**! You've just erased an entire category of important bugs before you even ran the code. In fact, this is how most of nullable values is handled:
4061+
4062+
4063+
4064+If you don't handle the `None` case, the compiler warns. No more `undefined` bugs in your code!
4065+
4066+## Conclusion & Tips & Tricks
4067+
4068+Hopefully you can see how pattern matching is a game changer for writing correct code, through the concise destructuring syntax, the proper conditions handling of `switch`, and the static exhaustiveness check.
4069+
4070+Below is some advice:
4071+
4072+Avoid using the wildcard `_` unnecessarily. Using the wildcard `_` will bypass the compiler's exhaustiveness check. Consequently, the compiler will not be able to notify you of probable errors when you add a new case to a variant. Try only using `_` against infinite possibilities, e.g. string, int, etc.
4073+
4074+Use the `if` clause sparingly.
4075+
4076+**Flatten your pattern-match whenever you can**. This is a real bug remover. Here's a series of examples, from worst to best:
4077+
4078+
4079+
4080+Now that's just silly =). Let's turn it into pattern-matching:
4081+
4082+
4083+
4084+Slightly better, but still nested. Pattern-matching allows you to do this:
4085+
4086+
4087+
4088+Much more linear-looking! Now, you might be tempted to do this:
4089+
4090+
4091+
4092+Which is much more concise, but kills the exhaustiveness check mentioned above; refrain from using that. This is the best:
4093+
4094+
4095+
4096+Pretty darn hard to make a mistake in this code at this point! Whenever you'd like to use an if-else with many branches, prefer pattern matching instead. It's more concise and [performant](./variant.mdx#design-decisions) too.
4097+# Pipe
4098+
4099+ReScript provides a tiny but surprisingly useful operator `->`, called the "pipe", that allows you to "flip" your code inside-out. `a(b)` becomes `b->a`. It's a simple piece of syntax that doesn't have any runtime cost.
4100+
4101+Why would you use it? Imagine you have the following:
4102+
4103+
4104+
4105+This is slightly hard to read, since you need to read the code from the innermost part, to the outer parts. Use pipe to streamline it:
4106+
4107+
4108+
4109+Basically, `parseData(person)` is transformed into `person->parseData`, and `getAge(person->parseData)` is transformed into `person->parseData->getAge`, etc.
4110+
4111+**This works when the function takes more than one argument too**.
4112+
4113+
4114+
4115+is the same as
4116+
4117+
4118+
4119+This also works with labeled arguments.
4120+
4121+Pipes are used to emulate object-oriented programming. For example, `myStudent.getName` in other languages like Java would be `myStudent->getName` in ReScript (equivalent to `getName(myStudent)`). This allows us to have the readability of OOP without the downside of dragging in a huge class system just to call a function on a piece of data.
4122+
4123+## Tips & Tricks
4124+
4125+Do **not** abuse pipes; they're a means to an end. Inexperienced engineers sometimes shape a library's API to take advantage of the pipe. This is backwards.
4126+
4127+## JS Method Chaining
4128+
4129+[bind to JS function](./bind-to-js-function.mdx) docs
4130+
4131+JavaScript's APIs are often attached to objects, and are often chainable, like so:
4132+
4133+
4134+
4135+Assuming we don't need the chaining behavior above, we'd bind to each case of this using [`@send`](../../syntax-lookup/decorator_send.mdx) from the aforementioned binding API page:
4136+
4137+
4138+
4139+You'd use them like this:
4140+
4141+
4142+
4143+This looks much worse than the JS counterpart! Clean it up visually with pipe:
4144+
4145+
4146+
4147+## Pipe Into Variants
4148+
4149+You can pipe into a variant's constructor as if it was a function:
4150+
4151+
4152+
4153+We turn this into:
4154+
4155+
4156+
4157+**Note** that using a variant constructor as a function wouldn't work anywhere else beside here.
4158+
4159+## Pipe Placeholders
4160+
4161+A placeholder is written as an underscore and it tells ReScript that you want to fill in an argument of a function later. These two have equivalent meaning:
4162+
4163+
4164+
4165+Sometimes you don't want to pipe the value you have into the first position. In these cases you can mark a placeholder value to show which argument you would like to pipe into.
4166+
4167+Let's say you have a function `namePerson`, which takes a `person` then a `name` argument. If you are transforming a person then pipe will work as-is:
4168+
4169+
4170+
4171+If you have a name that you want to apply to a person object, you can use a placeholder:
4172+
4173+
4174+
4175+This allows you to pipe into any positional argument. It also works for named arguments:
4176+
4177+
4178+# Polymorphic Variant
4179+
4180+Polymorphic variants (or poly variant) are a cousin of [variant](./variant.mdx). With these differences:
4181+
4182+- They start with a `#` and the constructor name doesn't need to be capitalized.
4183+- They don't require an explicit type definition. The type is inferred from usage.
4184+- Values of different poly variant types can share the constructors they have in common (aka, poly variants are "structurally" typed, as opposed to ["nominally" typed](./variant.mdx#variant-types-are-found-by-field-name)).
4185+
4186+They're a convenient and useful alternative to regular variants, but should **not** be abused. See the drawbacks at the end of this page.
4187+
4188+## Creation
4189+
4190+We provide 3 syntaxes for a poly variant's constructor:
4191+
4192+
4193+
4194+**Take a look at the output**. Poly variants are _great_ for JavaScript interop. For example, you can use it to model JavaScript string and number enums like TypeScript, but without confusing their accidental usage with regular strings and numbers.
4195+
4196+`myColor` uses the common syntax. The second and third syntaxes are to support expressing strings and numbers more conveniently. We allow the second one because otherwise it'd be invalid syntax since symbols like `-` and others are usually reserved.
4197+
4198+## Type Declaration
4199+
4200+Although **optional**, you can still pre-declare a poly variant type:
4201+
4202+
4203+
4204+These types can also be inlined, unlike for regular variant:
4205+
4206+
4207+
4208+**Note**: because a poly variant value's type definition is **inferred** and not searched in the scope, the following snippet won't error:
4209+
4210+
4211+
4212+That `myColor` parameter's type is inferred to be `#red`, `#green` or `#yellow`, and is unrelated to the `color` type. If you intended `myColor` to be of type `color`, annotate it as `myColor: color` in any of the places.
4213+
4214+## Constructor Arguments
4215+
4216+This is similar to a regular variant's [constructor arguments](./variant.mdx#constructor-arguments):
4217+
4218+
4219+
4220+### Combine Types and Pattern Match
4221+
4222+You can use poly variant types within other poly variant types to create a sum of all constructors:
4223+
4224+
4225+
4226+There's also some special [pattern matching](./pattern-matching-destructuring.mdx) syntax to match on constructors defined in a specific poly variant type:
4227+
4228+
4229+
4230+This is a shorter version of:
4231+
4232+
4233+
4234+## Structural Sharing
4235+
4236+Since poly variants value don't have a source of truth for their type, you can write such code:
4237+
4238+
4239+
4240+With a regular variant, the line `displayColor(myColor)` would fail, since it'd complain that the type of `myColor` doesn't match the type of `v`. No problem with poly variant.
4241+
4242+## JavaScript Output
4243+
4244+Poly variants are great for JavaScript interop! You can share their values to JS code, or model incoming JS values as poly variants.
4245+
4246+- `#red` and `#"I am red 😃"` compile to JavaScipt `"red"` and `"I am red 😃"`.
4247+- `#1` compiles to JavaScript `1`.
4248+- Poly variant constructor with 1 argument, like `Instagram("Jenny")` compile to a straightforward `{NAME: "Instagram", VAL: "Jenny"}`. 2 or more arguments like `#Facebook("Josh", 26)` compile to a similar object, but with `VAL` being an array of the arguments.
4249+
4250+### Bind to Functions
4251+
4252+For example, let's assume we want to bind to `Intl.NumberFormat` and want to make sure that our users only pass valid locales, we could define an external binding like this:
4253+
4254+
4255+
4256+The JS output is identical to handwritten JS, but we also get to enjoy type errors if we accidentally write `makeNumberFormat(#"de-DR")`.
4257+
4258+More advanced usage examples for poly variant interop can be found in [Bind to JS Function](./bind-to-js-function.mdx#constrain-arguments-better).
4259+
4260+### Bind to String Enums
4261+
4262+Let's assume we have a TypeScript module that expresses following enum export:
4263+
4264+
4265+
4266+For this particular example, we can also inline poly variant type definitions to design the type for the imported `myDirection` value:
4267+
4268+
4269+
4270+Again: since we were using poly variants, the JS Output is practically zero-cost and doesn't add any extra code!
4271+
4272+## Extra Constraints on Types
4273+
4274+The previous poly variant type annotations we've looked at are the regular "closed" kind. However, there's a way to express "I want at least these constructors" (lower bound) and "I want at most these constructors" (upper bound):
4275+
4276+
4277+
4278+**Note:** We added this info for educational purposes. In most cases you will not want to use any of this stuff, since it makes your APIs pretty unreadable / hard to use.
4279+
4280+### Closed `[`
4281+
4282+This is the simplest poly variant definition, and also the most practical one. Like a common variant type, this one defines an exact set of constructors.
4283+
4284+
4285+
4286+In the example above, `color` will only allow one of the three constructors that are defined in the `rgb` type. This is usually the way how poly variants should be defined.
4287+
4288+In case you want to define a type that is extensible, you'll need to use the lower / upper bound syntax.
4289+
4290+### Lower Bound `[>`
4291+
4292+A lower bound defines the minimum set of constructors a poly variant type is aware of. It is also considered an "open poly variant type", because it doesn't restrict any additional values.
4293+
4294+Here is an example on how to make a minimum set of `basicBlueTones` extensible for a new `color` type:
4295+
4296+
4297+
4298+Here, the compiler will enforce the user to define `#Blue | #DeepBlue | #LightBlue` as the minimum set of constructors when trying to extend `basicBlueTone<'a>`.
4299+
4300+**Note:** Since we want to define an extensible poly variant, we need to provide a type placeholder `<'a>`, and also add `as 'a` after the poly variant declaration, which essentially means: "Given type `'a` is constraint to the minimum set of constructors (`#Blue | #DeepBlue | #LightBlue`) defined in `basicBlueTone`".
4301+
4302+### Upper Bound `[<`
4303+
4304+The upper bound works in the opposite way than a lower bound: the extending type may only use constructors that are stated in the upper bound constraint.
4305+
4306+Here another example, but with red colors:
4307+
4308+
4309+
4310+## Coercion
4311+
4312+You can convert a poly variant to a `string` or `int` at no cost:
4313+
4314+
4315+
4316+**Note**: for the coercion to work, the poly variant type needs to be closed; you'd need to annotate it, since otherwise, `theCompany` would be inferred as `[> #Apple]`.
4317+
4318+## Tips & Tricks
4319+
4320+### Variant vs Polymorphic Variant
4321+
4322+One might think that polymorphic variants are superior to regular [variants](./variant.mdx). As always, there are trade-offs:
4323+
4324+- Due to their "structural" nature, poly variant's type errors might be more confusing. If you accidentally write `#blur` instead of `#blue`, ReScript will still error but can't indicate the correct source as easily. Regular variants' source of truth is the type definition, so the error can't go wrong.
4325+- It's also harder to refactor poly variants. Consider this:
4326+
4327+
4328+
4329+ Refactoring the first one to `#Orange` doesn't mean we should refactor the third one. Therefore, the editor plugin can't touch the second one either. Regular variant doesn't have such problem, as these 2 values presumably come from different variant type definitions.
4330+
4331+- You might lose some nice pattern match checks from the compiler:
4332+
4333+
4334+
4335+ Because there's no poly variant definition, it's hard to know whether the `#blue` case can be safely removed.
4336+
4337+In most scenarios, we'd recommend to use regular variants over polymorphic variants, especially when you are writing plain ReScript code. In case you want to write zero-cost interop bindings or generate clean JS output, poly variants are oftentimes a better option.
4338+# Primitive Types
4339+
4340+ReScript comes with the familiar primitive types like `string`, `int`, `float`, etc.
4341+
4342+{/* TODO: doc unit */}
4343+
4344+## String
4345+
4346+ReScript `string`s are delimited using **double** quotes (single quotes are reserved for the character type below).
4347+
4348+
4349+
4350+To concatenate strings, use `++`:
4351+
4352+
4353+
4354+Since both sides of the concatenation are known, the JS output becomes a single string literal.
4355+
4356+### String Interpolation
4357+
4358+There's a special syntax for string that allows
4359+
4360+- multiline string just like before
4361+- no special character escaping
4362+- Interpolation
4363+
4364+
4365+
4366+This is just like JavaScript's backtick string interpolation, except without needing to escape special characters.
4367+
4368+### Usage
4369+
4370+See the familiar `String` API in the [API docs](/docs/manual/api/stdlib/string). Since a ReScript string maps to a JavaScript string, you can mix & match the string operations in all standard libraries.
4371+
4372+### Tips & Tricks
4373+
4374+**You have a good type system now!** In an untyped language, you'd often overload the meaning of string by using it as:
4375+
4376+- a unique id: `var BLUE_COLOR = "blue"`
4377+- an identifier into a data structure: `var BLUE = "blue" var RED = "red" var colors = [BLUE, RED]`
4378+- the name of an object field: `person["age"] = 24`
4379+- an enum: `if (audio.canPlayType() === 'probably') {...}` [(ಠ_ಠ)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType#Return_value)
4380+- other crazy patterns you'll soon find horrible, after getting used to ReScript's alternatives.
4381+
4382+The more you overload the poor string type, the less the type system (or a teammate) can help you! ReScript provides concise, fast and maintainable types & data structures alternatives to the use-cases above (e.g. [variants](./variant.mdx)).
4383+
4384+## Char
4385+
4386+ReScript has a type for a string with a single letter:
4387+
4388+
4389+
4390+**Note**: Char doesn't support Unicode or UTF-8 and is therefore not recommended.
4391+
4392+To convert a String to a Char, use `String.get("a", 0)`. To convert a Char to a String, use `String.make(1, 'a')`.
4393+
4394+## Regular Expression
4395+
4396+ReScript regular expressions compile cleanly to their JavaScript counterpart:
4397+
4398+
4399+
4400+A regular expression like the above has the type `RegExp.t`. The [RegExp](/docs/manual/api/stdlib/regexp) module contains the regular expression helpers you have seen in JS.
4401+
4402+## Boolean
4403+
4404+A ReScript boolean has the type `bool` and can be either `true` or `false`. Common operations:
4405+
4406+- `&&`: logical and.
4407+- `||`: logical or.
4408+- `!`: logical not.
4409+- `<=`, `>=`, `<`, `>`
4410+- `==`: structural equal, compares data structures deeply. `(1, 2) == (1, 2)` is `true`. Convenient, but use with caution.
4411+- `===`: referential equal, compares shallowly. `(1, 2) === (1, 2)` is `false`. `let myTuple = (1, 2); myTuple === myTuple` is `true`.
4412+- `!=`: structural unequal.
4413+- `!==`: referential unequal.
4414+
4415+ReScript's `true/false` compiles into a JavaScript `true/false`.
4416+
4417+## Integers
4418+
4419+32-bits, truncated when necessary. We provide the usual operations on them: `+`, `-`, `*`, `/`, etc. See [Int](/docs/manual/api/stdlib/int) for helper functions.
4420+
4421+Integer operators include `+`, `-`, `*`, `/`, `**`, and `%`.
4422+
4423+`%` keeps the familiar `mod` naming, but its semantics are remainder (same behavior as JavaScript `%`).
4424+
4425+Bitwise operators for `int`: `~~~`, `&&&`, `|||`, `^^^`, `<<`, `>>`, `>>>`.
4426+
4427+**Be careful when you bind to JavaScript numbers!** Since ReScript integers have a much smaller range than JavaScript numbers, data might get lost when dealing with large numbers. In those cases it’s much safer to bind the numbers as **float**. Be extra mindful of this when binding to JavaScript Dates and their epoch time.
4428+
4429+To improve readability, you may place underscores in the middle of numeric literals such as `1_000_000`. Note that underscores can be placed anywhere within a number, not just every three digits.
4430+
4431+## Floats
4432+
4433+Arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`) work for both `int` and `float`. Like `0.5 + 0.6`. See [Float](/docs/manual/api/stdlib/float) for helper functions.
4434+
4435+As with integers, you may use underscores within literals to improve readability.
4436+
4437+### Int-to-Float Coercion
4438+
4439+`int` values can be coerced to `float` with the `:>` (type coercion) operator.
4440+
4441+
4442+
4443+## Big Integers (experimental)
4444+
4445+**Since 11.1**
4446+
4447+For values which are too large to be represented by Int or Float, there is the `bigint` primitive type.
4448+We provide the usual operations on them: `+`, `-`, `*`, `/`, `**`, `%`, etc. See [BigInt](/docs/manual/api/stdlib/bigint) for helper functions.
4449+
4450+A `bigint` number is denoted by a trailing `n` like so: `42n`.
4451+
4452+As `bigint` is a different data type than `int`, it's necessary to open the corresponding module to overload the operators.
4453+
4454+
4455+
4456+It also supports all the bitwise operations, except unsigned shift right (`>>>`), which is not supported by JS itself for `bigint`s.
4457+
4458+
4459+
4460+It can also be pattern-matched.
4461+
4462+
4463+
4464+## Unit
4465+
4466+The `unit` type indicates the absence of a specific value. It has only a single value, `()`, which acts as a placeholder when no other value exists or is needed. It compiles to JavaScript's `undefined` and resembles the `void` type in languages such as C++. What's the point of such a type?
4467+
4468+Consider the `Math.random` function. Its type signature is `unit => float`, which means it receives a `unit` as input and calculates a random `float` as output. You use the function like this - `let x = Math.random()`. Notice `()` as the first and only function argument.
4469+
4470+Imagine a simplified `Console.log` function that prints a message. Its type signature is `string => unit` and you'd use it like this `Console.log("Hello!")`. It takes a string as input, prints it, and then returns nothing useful. When `unit` is the output of a function it means the function performs some kind of side-effect.
4471+
4472+## Unknown
4473+
4474+The `unknown` type represents values with contents that are a mystery or are not 100% guaranteed to be what you think they are. It provides type-safety when interacting with data received from an untrusted source. For example, suppose an external function is supposed to return a `string`. It might. But if the documentation is not accurate or the code has bugs, the function could return `null`, an `array`, or something else you weren't expecting.
4475+
4476+The ReScript type system helps you avoid run-time crashes and unpredicatable behavior by preventing you from using `unknown` in places that expect a `string` or `int` or some other type. The ReScript core libraries also provide utility functions to help you inspect `unknown` values and access their contents. In some cases you may need a JSON parsing library to convert `unknown` values to types you can safely use.
4477+
4478+Consider using `unknown` when receiving data from [external JavaScript functions](./bind-to-js-function.mdx)
4479+# Project Structure
4480+
4481+These are the existing, non-codified community practices that are currently propagated through informal agreement. We might remove some of them at one point, and enforce some others. Right now, they're just recommendations for ease of newcomers.
4482+
4483+## File Casing
4484+
4485+Capitalized file names (aka first letter upper-cased).
4486+
4487+**Justification**: Module names can only be capitalized. Newcomers often ask how a file maps to a module, and why `draw.res` maps to the module `Draw`, and sometimes try to refer to a module through uncapitalized identifiers. Using `Draw.res` makes this mapping more straightforward. It also helps certain file names that'd be awkward in uncapitalized form: `uRI.res`.
4488+
4489+## Ignore `.merlin` File
4490+
4491+This is generated by the build system and you should not have to manually edit it. Don't check it into the repo.
4492+
4493+**Justification**: `.merlin` is for editor tooling. The file contains absolute paths, which are also not cross-platform (e.g. Windows paths are different).
4494+
4495+## Folders
4496+
4497+Try not to have too many nested folders. Keep your project flat, and have fewer files (reminder: you can use nested modules).
4498+
4499+**Justification**: The file system is a _tree_, but your code's dependencies are a _graph_. Because of that, any file & folder organization is usually imperfect. While it's still valuable to group related files together in a folder, the time wasted debating & getting decision paralysis over these far outweight their benefits. We'll always recommend you to Get Work Done instead of debating about these issues.
4500+
4501+## Third-party Dependencies
4502+
4503+Keep them to a minimum.
4504+
4505+**Justification**: A compiled, statically typed language cannot model its dependencies easily by muddling along like in a dynamic language, especially when we're still piggy-backing on NPM/Yarn (to reduce learning overhead in the medium-term). Keeping dependencies simple & lean helps reduce possibility of conflicts (e.g. two diamond dependencies, or clashing interfaces).
4506+
4507+## Documentation
4508+
4509+Have them. Spend more effort making them great (examples, pitfalls) and professional rather than _just_ fancy-looking. Do use examples, and avoid using names such as `foo` and `bar`. There's always more concrete names (it's an example, no need to be abstract/generalized just yet. The API docs will do this plentily). For blog posts, don't repeat the docs themselves, describe the _transition_ from old to new, and why (e.g. "it was a component, now it's a function, because ...").
4510+
4511+**Justification**: It's hard for newcomers to distinguish between a simple/decent library and one that's fancy-looking. For the sake of the community, don't try too hard to one-up each other's libraries. Do spread the words, but use your judgement too.
4512+
4513+## PPX & Other Meta-tools
4514+
4515+Keep them to a minimum. PPX, unless used in renown cases (printer, accessors and serializer/deserializer generation), can cause big learning churn for newcomers; on top of the syntax, semantics, types, build tool & FFI that they already have to learn, learning per-library custom transformations of the code is an extra step. More invasive macros makes the code itself less semantically meaningful too, since the essence would be hiding somewhere else.
4516+
4517+## Paradigm
4518+
4519+Don't abuse overly fancy features. Do leave some breathing room for future APIs but don't over-architect things.
4520+
4521+**Justification**: Simple code helps newcomers understand and potentially contribute to your code. Contributing is the best way for them to learn. The extra help you receive might also surpass the gain of using a slightly more clever language trick. But do try new language tricks in some of more casual projects! You might discover new ways of architecting code.
4522+
4523+## Publishing
4524+
4525+If it's a wrapper for a JS library, don't publish the JS artifacts. If it's a legit library, publish the artifacts in lib/js if you think JS consumers might use it. This is especially the case when you gradually convert a JS lib to ReScript while not breaking existing JS consumers.
4526+
4527+Do put the keywords `"rescript"` in your package.json `keywords` field. This allows us to find the library much more easily for future purposes.
4528+
4529+**Justification**: Be nice to JS consumers of your library. They're your future ReScripters.
4530+# Promise
4531+
4532+> **Note:** Starting from ReScript 10.1 and above, we recommend using [async / await](./async-await.mdx) when interacting with Promises.
4533+
4534+## `promise` type
4535+
4536+**Since 10.1**
4537+
4538+In ReScript, every JS promise is represented with the globally available `promise<'a>` type.
4539+
4540+Here's a usage example in a function signature:
4541+
4542+
4543+
4544+To work with promise values (instead of using `async` / `await`) you may want to use the built-in `Promise` module.
4545+
4546+## Promise
4547+
4548+A builtin module to create, chain and manipulate promises.
4549+
4550+### Creating a promise
4551+
4552+
4553+
4554+### Access the contents and transform a promise
4555+
4556+
4557+
4558+For comparison, the `async` / `await` version of the same code would look like this:
4559+
4560+
4561+
4562+Needless to say, the async / await version offers better ergonomics and less opportunities to run into type issues.
4563+
4564+### Handling Rejected Promises
4565+
4566+You can handle a rejected promise using the [`Promise.catch()`](/docs/manual/api/stdlib/promise#value-catch) method, which allows you to catch and manage errors effectively.
4567+
4568+### Run multiple promises in parallel
4569+
4570+In case you want to launch multiple promises in parallel, use `Promise.all`:
4571+
4572+
4573+# Record
4574+
4575+Records are like JavaScript objects but:
4576+
4577+- are immutable by default
4578+- have fixed fields (not extensible)
4579+
4580+## Type Declaration
4581+
4582+A record needs a mandatory type declaration:
4583+
4584+
4585+
4586+You can also nest definitions of records.
4587+
4588+
4589+
4590+Nesting record definitions is a nice way to group records that are part of the same structure, and won't be referenced from the outside.
4591+
4592+If you end up needing to refer to a nested record type explicitly, you should make it an explicit definition instead of a nested one. This is mainly for 2 reasons:
4593+
4594+- The records that are automatically generated for the nested record definitions are named in a way that would require you to use escaped identifiers to reference them. The nested record at `notificationSettings` above would be named `\"person.notificationSettings"` for instance
4595+- For the sake of clarity (and caring about your co-workers), having an explicit and named definition to look at and refer to is much easier than scanning a potentially large record definition for the nested record you're looking for
4596+
4597+So if we in the example above ended up needing to refer to `person.notificationSettings` nested record from the outside, we should instead make it explicit, just like how we normally define records:
4598+
4599+
4600+
4601+## Creation
4602+
4603+To create a `person` record (declared above):
4604+
4605+
4606+
4607+When you create a new record value, ReScript tries to find a record type declaration that conforms to the shape of the value. So the `me` value here is inferred as of type `person`.
4608+
4609+The type is found by looking above the `me` value. **Note**: if the type instead resides in another file or module, you need to explicitly indicate which file or module it is:
4610+
4611+
4612+
4613+
4614+
4615+In both `me` and `me2` the record definition from `School` is found. The first one, `me` with the regular type annotation, is preferred.
4616+
4617+## Access
4618+
4619+Use the familiar dot notation:
4620+
4621+
4622+
4623+## Immutable Update
4624+
4625+New records can be created from old records with the `...` spread operator. The original record isn't mutated.
4626+
4627+
4628+
4629+**Note**: spread cannot add new fields to the record value, as a record's shape is fixed by its type.
4630+
4631+## Mutable Update
4632+
4633+Record fields can optionally be mutable. This allows you to efficiently update those fields in-place with the `=` operator.
4634+
4635+
4636+
4637+Fields not marked with `mutable` in the type declaration cannot be mutated.
4638+
4639+## JavaScript Output
4640+
4641+ReScript records compile to straightforward JavaScript objects; see the various JS output tabs above.
4642+
4643+## Optional Record Fields
4644+
4645+ReScript [`v10`](../../blog/release-10-0-0.mdx#experimental-optional-record-fields) introduced optional record fields. This means that you can define fields that can be omitted when creating the record. It looks like this:
4646+
4647+
4648+
4649+Notice how `name` has a suffixed `?`. That means that the field itself is _optional_.
4650+
4651+### Creation
4652+
4653+You can omit any optional fields when creating a record. Not setting an optional field will default the field's value to `None`:
4654+
4655+
4656+
4657+This has consequences for pattern matching, which we'll expand a bit on soon.
4658+
4659+## Immutable Update
4660+
4661+Updating an optional field via an immutable update above lets you set that field value without needing to care whether it's optional or not.
4662+
4663+
4664+
4665+However, if you want to set the field to an optional value, you prefix that value with `?`:
4666+
4667+
4668+
4669+You can unset an optional field's value via that same mechanism by setting it to `?None`.
4670+
4671+### Pattern Matching on Optional Fields
4672+
4673+[Pattern matching](./pattern-matching-destructuring.mdx), one of ReScript's most important features, has two caveats when you deal with optional fields.
4674+
4675+When matching on the value directly, it's an `option`. Example:
4676+
4677+
4678+
4679+But, when matching on the field as part of the general record structure, it's treated as the underlying, non-optional value:
4680+
4681+
4682+
4683+Sometimes you _do_ want to know whether the field was set or not. You can tell the pattern matching engine about that by prefixing your option match with `?`, like this:
4684+
4685+
4686+
4687+## Record Type Spread
4688+
4689+In ReScript v11, you can now spread one or more record types into a new record type. It looks like this:
4690+
4691+
4692+
4693+`type c` will now be:
4694+
4695+
4696+
4697+Record type spreads act as a 'copy-paste' mechanism for fields from one or more records into a new record. This operation inlines the fields from the spread records directly into the new record definition, while preserving their original properties, such as whether they are optional or mandatory. It's important to note that duplicate field names are not allowed across the records being spread, even if the fields have the same type.
4698+
4699+## Record Type Coercion
4700+
4701+Record type coercion gives us more flexibility when passing around records in our application code. In other words, we can now coerce a record `a` to be treated as a record `b` at the type level, as long as the original record `a` contains the same set of fields in `b`. Here's an example:
4702+
4703+
4704+
4705+Notice how we _coerced_ the value `a` to type `b` using the coercion operator `:>`. This works because they have the same record fields. This is purely at the type level, and does not involve any runtime operations.
4706+
4707+Additionally, we can also coerce records from `a` to `b` whenever `a` is a super-set of `b` (i.e. `a` containing all the fields of `b`, and more). The same example as above, slightly altered:
4708+
4709+
4710+
4711+Notice how `a` now has more fields than `b`, but we can still coerce `a` to `b` because `b` has a subset of the fields of `a`.
4712+
4713+In combination with [optional record fields](./record.mdx#optional-record-fields), one may coerce a mandatory field of an `option` type to an optional field:
4714+
4715+
4716+
4717+## Tips & Tricks
4718+
4719+### Record Types Are Found By Field Name
4720+
4721+With records, you **cannot** say "I'd like this function to take any record type, as long as they have the field `age`". The following **won't work as intended**:
4722+
4723+
4724+
4725+Instead, `getAge` will infer that the parameter `entity` must be of type `monster`, the closest record type with the field `age`. The following code's last line fails:
4726+
4727+
4728+
4729+The type system will complain that `me` is a `person`, and that `getAge` only works on `monster`. If you need such capability, use ReScript objects, described [here](./object.mdx).
4730+
4731+### Optional Fields in Records Can Be Useful for Bindings
4732+
4733+Many JavaScript APIs tend to have large configuration objects that can be a bit annoying to model as records, since you previously always needed to specify all record fields when creating a record.
4734+
4735+Optional record fields, introduced in [`v10`](../../blog/release-10-0-0.mdx#experimental-optional-record-fields), is intended to help with this. Optional fields will let you avoid having to specify all fields, and let you just specify the one's you care about. A significant improvement in ergonomics for bindings and other APIs with for example large configuration objects.
4736+
4737+## Design Decisions
4738+
4739+Why use records instead of objects?
4740+
4741+1. The truth is that most of the times in your app, your data's shape is actually fixed, and if it's not, it can potentially be better represented as a combination of variant (introduced next) + record instead.
4742+
4743+2. Since a record type is resolved through finding that single explicit type declaration (we call this "nominal typing"), the type error messages end up better than the counterpart ("structural typing", like for tuples). This makes refactoring easier; changing a record type's fields naturally allows the compiler to know that it's still the same record, just misused in some places. Otherwise, under structural typing, it might get hard to tell whether the definition site or the usage site is wrong.
4744+# ReScript for JavaScript Developers
4745+
4746+If you already write JavaScript, ReScript should feel familiar quickly. This page is a compact syntax guide for the main differences you should be aware of.
4747+
4748+For a guided migration workflow, see [Converting from JS](./converting-from-js.mdx).
4749+
4750+## What to know first
4751+
4752+- `let` bindings are immutable by default. See [Let Binding](./let-binding.mdx) and [Mutation](./mutation.mdx).
4753+- ReScript does not use `null` and `undefined` as normal control flow. Reach for `option` instead. See [Null, Undefined and Option](./null-undefined-option.mdx).
4754+- Arrays must contain values of the same type. See [Array and List](./array-and-list.mdx) and [Tuple](./tuple.mdx).
4755+- Records are not ad-hoc JS objects; they have known field names and types. See [Record](./record.mdx) and [Object](./object.mdx).
4756+- Conditionals and blocks return values, so expression-oriented code is common. See [If-Else & Loops](./control-flow.mdx).
4757+- Pattern matching replaces many ad-hoc `if` or property-check branches. See [Pattern Matching / Destructuring](./pattern-matching-destructuring.mdx).
4758+
4759+## Quick reference
4760+
4761+| Topic | ReScript | Notes for JavaScript developers |
4762+| --------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
4763+| Semicolons | `let x = 1` | Semicolons are not required. See [Overview](./overview.mdx#semicolons). |
4764+| Comments | `//`, `/* */`, `/** */` | Familiar syntax, including doc comments. See [Overview](./overview.mdx#comments). |
4765+| Variables | `let x = 5` | `let` creates an immutable binding. See [Let Binding](./let-binding.mdx). |
4766+| Mutation | `let x = ref(5)` | Mutable state is explicit through `ref` or mutable fields. See [Mutation](./mutation.mdx). |
4767+| Strings | `"hello"` | Strings use double quotes. See [Primitive Types](./primitive-types.mdx). |
4768+| String concatenation | `"hello " ++ name` | ReScript uses `++` for strings. See [Primitive Types](./primitive-types.mdx). |
4769+| Interpolation | `` `hello ${name}` `` | Template strings work similarly. See [Primitive Types](./primitive-types.mdx). |
4770+| Equality | `===`, `!==`, `==`, `!=` | No coercive equality. `==` and `!=` are structural. See [Equality and Comparison](./equality-comparison.mdx). |
4771+| Numbers | `3`, `3.14`, `2.0 * 3.0` | Arithmetic operators work for both `int` and `float`. See [Primitive Types](./primitive-types.mdx). |
4772+| Records | `{x: 30, y: 20}` | Similar object syntax, but records are typed. See [Record](./record.mdx). |
4773+| Arrays | `[1, 2, 3]` | Arrays are homogeneous. See [Array and List](./array-and-list.mdx). |
4774+| Mixed fixed-size data | `(1, "Bob", true)` | Use tuples instead of heterogeneous arrays. See [Tuple](./tuple.mdx). |
4775+| Missing values | `option<'a>` | Use `Some(value)` and `None` instead of `null` and `undefined`. See [Null, Undefined and Option](./null-undefined-option.mdx). |
4776+| Functions | `let add = (a, b) => a + b` | Familiar arrow-style syntax. See [Function](./function.mdx). |
4777+| Blocks | `{ let x = 1; x + 1 }` | The last expression is returned implicitly. See [Overview](./overview.mdx#blocks). |
4778+| Conditionals | `if cond {a} else {b}` | `if` is an expression. See [If-Else & Loops](./control-flow.mdx). |
4779+| Pattern matching | `switch value { ... }` | Use `switch` for destructuring and exhaustive branching. See [Pattern Matching / Destructuring](./pattern-matching-destructuring.mdx). |
4780+| Destructuring | `let {a, b} = data` | Works for records, arrays, tuples, and more. See [Pattern Matching / Destructuring](./pattern-matching-destructuring.mdx). |
4781+| Loops | `for i in 0 to 10 {}` | `for` and `while` exist, but collection transforms are also common. See [If-Else & Loops](./control-flow.mdx). |
4782+| Exceptions | `throw(MyException(...))` | `throw` and `try` exist, but typed data flow is preferred where possible. See [Exception](./exception.mdx). |
4783+| JSX | `<Comp message />` | JSX is supported directly, with a few ReScript conventions. See [JSX](./jsx.mdx). |
4784+
4785+## Where to Go Next
4786+
4787+- For a broader syntax reference, see [Overview](./overview.mdx).
4788+- For a migration workflow inside an existing codebase, see [Converting from JS](./converting-from-js.mdx).
4789+- For JavaScript interop, see [Interop Cheatsheet](./interop-cheatsheet.mdx).
4790+- For importing and exporting JS modules, see [Import from Export to JS](./import-from-export-to-js.mdx).
4791+- For binding to JS objects and functions, see [Bind to JS Object](./bind-to-js-object.mdx) and [Bind to JS Function](./bind-to-js-function.mdx).
4792+# Reserved Keywords
4793+
4794+> **Note**: Some of these words are reserved purely for backward compatibility.
4795+>
4796+> If you _need_ to use one of these names as binding and/or field name, see [Use Illegal Identifier Names](./use-illegal-identifier-names.mdx).
4797+
4798+- `and`
4799+- `as`
4800+- `assert`
4801+
4802+{/* - `begin` */}
4803+
4804+{/* - `class` */}
4805+
4806+- `constraint`
4807+
4808+{/* - `do` */}
4809+{/* - `done` */}
4810+
4811+- `else`
4812+ {/* - `end` */}
4813+ {/* - `esfun` */}
4814+- `exception`
4815+- `external`
4816+
4817+* `false`
4818+* `for`
4819+ {/* - `fun` */}
4820+ {/* - `function` */}
4821+ {/* - `functor` */}
4822+
4823+- `if`
4824+- `in`
4825+- `include`
4826+ {/* - `inherit` */}
4827+ {/* - `initializer` */}
4828+
4829+* `lazy`
4830+* `let`
4831+
4832+- `module`
4833+- `mutable`
4834+
4835+{/* - `new` */}
4836+{/* - `nonrec` */}
4837+
4838+{/* - `object` */}
4839+
4840+- `of`
4841+- `open`
4842+ {/* - `or` */}
4843+
4844+{/* - `pri` */}
4845+{/* - `pub` */}
4846+
4847+- `rec`
4848+
4849+{/* - `sig` */}
4850+{/* - `struct` */}
4851+
4852+- `switch`
4853+
4854+{/* - `then` */}
4855+
4856+- `true`
4857+- `try`
4858+- `type`
4859+
4860+{/* - `val` */}
4861+{/* - `virtual` */}
4862+
4863+- `when`
4864+- `while`
4865+- `with`
4866+# Scoped Polymorphic Types
4867+
4868+Scoped Polymorphic Types in ReScript are functions with the capability to handle arguments of any type within a specific scope. This feature is particularly valuable when working with JavaScript APIs, as it allows your functions to accommodate diverse data types while preserving ReScript's strong type checking.
4869+
4870+## Definition and Usage
4871+
4872+Scoped polymorphic types in ReScript offer a flexible and type-safe way to handle diverse data types within specific scopes. This documentation provides an example to illustrate their usage in a JavaScript context.
4873+
4874+### Example: Logging API
4875+
4876+Consider a logging example within a JavaScript context that processes various data types:
4877+
4878+
4879+
4880+In ReScript, we can bind to this function as a record with a scoped polymorphic function type:
4881+
4882+
4883+
4884+The `logger` type represents a record with a single field `log`, which is a scoped polymorphic function type `'a. 'a => unit`. The `'a` indicates a type variable that can be any type within the scope of the `log` function.
4885+
4886+Now, we can utilize the function obtained from `getLogger`:
4887+
4888+
4889+
4890+In this example, we create an instance of the logger by calling `getLogger()`, and then we can use the `log` function on the `myLogger` object to handle different data types.
4891+
4892+## Limitations of Normal Polymorphic Types
4893+
4894+Let's consider the same logging example in ReScript, but this time using normal polymorphic types:
4895+
4896+
4897+
4898+In this case, the `logger` type is a simple polymorphic function type `'a => unit`. However, when we attempt to use this type in the same way as before, we encounter an issue:
4899+
4900+
4901+
4902+The problem arises because the type inference in ReScript assigns a concrete type to the `logger` function based on the first usage. In this example, after the first call to `myLogger`, the compiler infers the type `logger<string>` for `myLogger`. Consequently, when we attempt to pass an argument of type `number` in the next line, a type error occurs because it conflicts with the inferred type `logger<string>`.
4903+
4904+In contrast, scoped polymorphic types, such as `'a. 'a => unit`, overcome this limitation by allowing type variables within the scope of the function. They ensure that the type of the argument is preserved consistently within that scope, regardless of the specific value used in the first invocation.
4905+
4906+## Limitations of Scoped Polymorphic Types
4907+
4908+Scoped polymorphic types work only when they are directly applied to let-bindings or record fields (as demonstrated in the logger example above). They can neither be applied to function bodies, nor to separate type definitions:
4909+
4910+
4911+# Shared Data Types
4912+
4913+ReScript's built-in values of type `string`, `float`, `array` and a few others have a rather interesting property: they compile to the exact same value in JavaScript!
4914+
4915+This means that if you're passing e.g. a ReScript string to the JavaScript side, the JavaScript side can directly use it as a native string. It also means that you can import a JavaScript string and use it as a native ReScript string.
4916+
4917+ReScript values compile to their JavaScript equivalents directly, so **no data converters are needed for most types**.
4918+
4919+**Shared, bidirectionally usable types**:
4920+
4921+- String. ReScript strings are JavaScript strings, vice-versa. (Caveat: only our backtick string `` `hello 👋 ${personName}` `` supports unicode and interpolation).
4922+- Float. ReScript floats are JavaScript numbers, vice-versa.
4923+- Array. Use the [Array API](/docs/manual/api/stdlib/array) for array operations.
4924+- Tuple. Compiles to an array at runtime. You can treat a fixed-sized, heterogenous JavaScript array as a ReScript tuple too.
4925+- Boolean.
4926+- Record. Record compiles to a JavaScript object. Therefore you can also treat JavaScript objects as records. If they're too dynamic, consider modeling them on the ReScript side as a hashmap/dictionary [`Dict`](/docs/manual/api/stdlib/dict) or a ReScript object.
4927+- Object. ReScript objects are JavaScript objects, vice-versa.
4928+- Function. They compile to clean JavaScript functions.
4929+- Module. ReScript files are considered top-level modules, and are compiled to JavaScript files 1 to 1. Nested modules are compiled to JavaScript objects.
4930+- Polymorphic variants.
4931+- Unit. The `unit` type, which has a single value `()`, compiles to `undefined` too. Likewise, you can treat an incoming `undefined` as `()` if that's the only value it'll ever be.
4932+
4933+**Types that are slightly different, but that you can still use from JavaScript**:
4934+
4935+- Int. **Ints are 32-bits**! Be careful, you can potentially treat them as JavaScript numbers and vice-versa, but if the number's large, then you better treat JavaScript numbers as floats. For example, we bind to `Date` using `float`s.
4936+- Option. The `option` type's `None` value compiles into `undefined`. The `Some` value, e.g. `Some(5)`, compiles to `5`. Likewise, you can treat an incoming `undefined` as `None`. **`null` isn't handled here**. If your JavaScript value can be `null`, use [Nullable](/docs/manual/api/stdlib/nullable) helpers.
4937+- Exception.
4938+- Variant. Check the compiled JavaScript output of variant to see its shape. We don't recommend exporting a ReScript variant for pure JavaScript usage, since they're harder to read as plain JavaScript code, but you can do it.
4939+- List, which is just a regular variant.
4940+
4941+**Non-shared types (aka internal types)**:
4942+
4943+- Character.
4944+- Int64.
4945+- Lazy values.
4946+- Everything else.
4947+
4948+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.
4949+
4950+These types require manual conversions if you want to export them for JavaScript consumption. For a seamless JavaScript/TypeScript integration experience, check out the [TypeScript Integration](./typescript-integration.mdx) page instead of doing conversions by hand.
4951+# Tagged templates
4952+
4953+**Since 11.1**
4954+
4955+Tagged templates provide a special form of string interpolation, enabling the creation of template literals
4956+where placeholders aren't restricted to strings. Moreover, the resulting output isn't confined solely to
4957+strings either. You can take a look at the [JS documentation
4958+about tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates)
4959+to learn more about them.
4960+
4961+## Define a tag function
4962+
4963+Tag functions in ReScript have the following signature:
4964+
4965+
4966+
4967+As you can see, you can have any type you want both for the placeholder array and for the output.
4968+
4969+Given how string interpolation works, you'll always have the following invariant:
4970+
4971+
4972+
4973+Let's say you want to interpolate strings with all kind of builtin types and make it work inside React components,
4974+you can define the following tag function:
4975+
4976+
4977+
4978+## Write tagged template literals
4979+
4980+Now that you have defined your tag function, you can use it this way:
4981+
4982+
4983+
4984+Pretty neat, isn't it? As you can see, it looks like any regular template literal but it accepts placeholders that are not strings
4985+and it outputs something that is not a string either, a `React.element` in this case.
4986+## Try Online
4987+
4988+Our [Playground](/try) lets you try ReScript online, and comes with the [ReScript React bindings](../react/introduction.mdx) and the new [ReScript Core](https://github.com/rescript-association/rescript-core) standard library preinstalled.
4989+# Tuple
4990+
4991+Tuples are a ReScript-specific data structure that don't exist in JavaScript. They are:
4992+
4993+- immutable
4994+- ordered
4995+- fix-sized at creation time
4996+- heterogeneous (can contain different types of values)
4997+
4998+
4999+
5000+Tuples' types can be used in type annotations as well. Tuple types visually resemble tuples values.
5001+
5002+
5003+
5004+**Note**: there's no tuple of size 1. You'd just use the value itself.
5005+
5006+## Usage
5007+
5008+To get a specific member of a tuple, destructure it:
5009+
5010+
5011+
5012+The `_` means you're ignoring the indicated members of the tuple.
5013+
5014+Tuples aren't meant to be updated mutatively. You'd create new ones by destructuring the old ones:
5015+
5016+
5017+
5018+## Tips & Tricks
5019+
5020+You'd use tuples in handy situations that pass around multiple values without too much ceremony. For example, to return many values:
5021+
5022+
5023+
5024+Try to keep the usage of tuple **local**. For data structures that are long-living and passed around often, prefer a **record**, which has named fields.
5025+# Type
5026+
5027+Types are the highlight of ReScript! They are:
5028+
5029+- **Strong**. A type can't change into another type. In JavaScript, your variable's type might change when the code runs (aka at runtime). E.g. a `number` variable might change into a `string` sometimes. This is an anti-feature; it makes the code much harder to understand when reading or debugging.
5030+- **Static**. ReScript types are erased after compilation and don't exist at runtime. Never worry about your types dragging down performance. You don't need type info during runtime; we report all the information (especially all the type errors) during compile time. Catch the bugs earlier!
5031+- **Sound**. This is our biggest differentiator versus many other typed languages that compile to JavaScript. Our type system is guaranteed to **never** be wrong. Most type systems make a guess at the type of a value and show you a type in your editor that's sometime incorrect. We don't do that. We believe that a type system that is sometime incorrect can end up being dangerous due to expectation mismatches.
5032+- **Fast**. Many developers underestimate how much of their project's build time goes into type checking. Our type checker is one of the fastest around.
5033+- **Inferred**. You don't have to write down the types! ReScript can deduce them from their values. Yes, it might seem magical that we can deduce all of your program's types, without incorrectness, without your manual annotation, and do so quickly. Welcome to ReScript =).
5034+
5035+The following sections explore more of our type system.
5036+
5037+## Inference
5038+
5039+This let-binding doesn't contain any written type:
5040+
5041+
5042+
5043+ReScript knows that `score` is an `int`, judging by the value `10`. This is called **inference**. Likewise, it also knows that the `add` function takes 2 `int`s and returns an `int`, judging from the `+` operator, which works on ints.
5044+
5045+## Type Annotation
5046+
5047+But you can also optionally write down the type, aka annotate your value:
5048+
5049+
5050+
5051+If the type annotation for `score` doesn't correspond to our inferred type for it, we'll show you an error during compilation time. We **won't** silently assume your type annotation is correct, unlike many other languages.
5052+
5053+You can also wrap any expression in parentheses and annotate it:
5054+
5055+
5056+
5057+Note: in the last line, `(~radius as r: int)` is a labeled argument. More on this in the [function](./function.mdx) page.
5058+
5059+## Type Alias
5060+
5061+You can refer to a type by a different name. They'll be equivalent:
5062+
5063+
5064+
5065+## Type Parameter (Aka Generic)
5066+
5067+Types can accept parameters, akin to generics in other languages. The parameters' names **need** to start with `'`.
5068+
5069+The use-case of a parameterized type is to kill duplications. Before:
5070+
5071+
5072+
5073+After:
5074+
5075+
5076+
5077+Note that the above codes are just contrived examples for illustration purposes. Since the types are inferred, you could have just written:
5078+
5079+
5080+
5081+The type system infers that it's a `(int, int, int)`. Nothing else needed to be written down.
5082+
5083+Type arguments appear in many places. Our `array<'a>` type is such a type that requires a type parameter.
5084+
5085+
5086+
5087+If types didn't accept parameters, the standard library would need to define the types `arrayOfString`, `arrayOfInt`, `arrayOfTuplesOfInt`, etc. That'd be tedious.
5088+
5089+Types can receive many arguments, and be composable.
5090+
5091+{/* TODO: too early for this example */}
5092+
5093+
5094+
5095+## Recursive Types
5096+
5097+Just like a function, a type can reference itself within itself using `rec`:
5098+
5099+
5100+
5101+## Mutually Recursive Types
5102+
5103+Types can also be _mutually_ recursive through `and`:
5104+
5105+
5106+
5107+## Type Escape Hatch
5108+
5109+ReScript's type system is robust and does not allow dangerous, unsafe stuff like implicit type casting, randomly guessing a value's type, etc. However, out of pragmatism, we expose a single escape hatch for you to "lie" to the type system:
5110+
5111+
5112+
5113+This declaration converts a `myType1` of your choice to `myType2` of your choice. You can use it like so:
5114+
5115+
5116+
5117+Obviously, do **not** abuse this feature. Use it tastefully when you're working with existing, overly dynamic JS code, for example.
5118+
5119+More on externals [here](./external.mdx).
5120+
5121+**Note**: this particular `external` is the only one that isn't preceded by a `@` [attribute](./attribute.mdx).
5122+# ReScript & TypeScript
5123+
5124+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".
5125+
5126+The implementation of genType performs a type-directed transformation of ReScript programs after compilation. The transformed programs operate on data types idiomatic to TypeScript.
5127+
5128+For example, a ReScript variant (which is represented as custom objects with tags at runtime):
5129+
5130+
5131+
5132+is exported to a TypeScript type:
5133+
5134+
5135+
5136+## A Quick Example
5137+
5138+Let's assume we are working on a TypeScript codebase and we want to integrate a single ReScript function.
5139+
5140+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.
5141+
5142+**That's exactly what genType was made for!**
5143+
5144+First we'll set up a function:
5145+
5146+
5147+
5148+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:
5149+
5150+
5151+
5152+genType automatically maps the `color` variant to TS via a string union type `"Red" | "Blue"`.
5153+
5154+Within our TypeScript application, we can now import and use the function in the following manner:
5155+
5156+
5157+
5158+## Exporting an entire module
5159+
5160+_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:
5161+
5162+
5163+
5164+## Setup
5165+
5166+Add a `gentypeconfig` section to your `rescript.json` (See [Configuration](./build-configuration.mdx#gentypeconfig) for details).
5167+
5168+Every `genType` powered project requires a configuration item `"gentypeconfig"` at top level in the project's `rescript.json`.
5169+
5170+The minimal configuration of genType is following:
5171+
5172+
5173+
5174+And don't forget to make sure `allowJs` is set to `true` in the project's `tsconfig.json`:
5175+
5176+
5177+
5178+### TypeScript Module Resolutions
5179+
5180+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.
5181+
5182+For example if the TypeScript project uses JavaScript modules with `Node16` / `NodeNext` module resolution:
5183+
5184+
5185+
5186+Then `moduleResolution` in `gentypeconfig` should be same value:
5187+
5188+
5189+
5190+In case of the TypeScript project using `Bundler` module resolution, `allowImportingTsExtensions` should also be `true`:
5191+
5192+
5193+
5194+
5195+
5196+## Testing the Whole Setup
5197+
5198+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).
5199+
5200+Save the file and rebuild the project via `npm run build:res` or similar. You should now see a `*.gen.tsx` file with the same name (e.g. `MyComponent.res` -> `MyComponent.gen.tsx`).
5201+
5202+Any values exported from `MyComponent.res` can then be imported from TypeScript. For example:
5203+
5204+
5205+
5206+## Experimental features
5207+
5208+These features are for experimentation only. They could be changed/removed any time, and not be considered breaking changes.
5209+
5210+- Export object and record types as interfaces. To activate, add `"exportInterfaces": true` to the configuration. The types are also renamed from `name` to `Iname`.
5211+
5212+## Shims
5213+
5214+A shim is a TS file that provides user-provided definitions for library types.
5215+
5216+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.
5217+
5218+- Example: `Array<string>` with format: `"RescriptModule=JavaScriptModule"`
5219+
5220+Configure your shim files within `"gentypeconfig"` in your [`rescript.json`]:
5221+
5222+
5223+
5224+and add relevant `.shim.ts` files in a directory which is visible by ReScript e.g.
5225+
5226+```
5227+├── rescript.json
5228+├── src
5229+│ ├── shims
5230+│ │ ├── Js.shim.ts
5231+│ │ ├── ReactEvent.shim.ts
5232+│ │ └── RescriptPervasives.shim.ts
5233+```
5234+
5235+Here are some examples:
5236+
5237+
5238+
5239+
5240+
5241+More complete example shims can be found [here](https://github.com/rescript-lang/rescript-compiler/blob/master/jscomp/gentype_tests/typescript-react-example/src/shims/).
5242+
5243+## Deprecated features
5244+
5245+Features related to generating runtimes were deprecated since v11 and should no longer be used.
5246+
5247+- **`@genType("alias")`** and **`@genType.as("alias")`**
5248+- **`@genType.opaque`**
5249+- **`@genType.import`**
5250+- TypeScript Shims
5251+
5252+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)).
5253+
5254+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.
5255+
5256+## Limitations
5257+
5258+- **in-source = true**. Currently only supports ReScript projects with [in-source generation](./build-configuration.mdx#package-specs) and file suffixes that end on `.js`, like `.res.js` or `.bs.js`.
5259+
5260+- **Limited namespace support**. Currently there's limited [namespace](./build-configuration.mdx#name-namespace) support, and only `namespace:true` is possible, not e.g. `namespace:"custom"`.
5261+# Use Illegal Identifier Names
5262+
5263+Sometime, for e.g. a let binding or a record field, you might want to use:
5264+
5265+- A capitalized name.
5266+- A name that contains illegal characters (e.g. emojis, hyphen, space).
5267+- A name that's one of ReScript's reserved keywords.
5268+
5269+We provide an escape hatch syntax for these cases:
5270+
5271+
5272+
5273+See the output. **Use them only when necessary**, for interop with JavaScript. This is a last-resort feature. If you abuse this, many of the compiler guarantees will go away.
5274+# Variant
5275+
5276+So far, most of ReScript's data structures might look familiar to you. This section introduces an extremely important, and perhaps unfamiliar, data structure: variant.
5277+
5278+Most data structures in most languages are about "this **and** that". A variant allows us to express "this **or** that".
5279+
5280+
5281+
5282+`myResponse` is a variant type with the cases `Yes`, `No` and `PrettyMuch`, which are called "variant constructors" (or "variant tag"). The `|` bar separates each constructor.
5283+
5284+**Note**: a variant's constructors need to be capitalized.
5285+
5286+## Variant Needs an Explicit Definition
5287+
5288+If the variant you're using is in a different file, bring it into scope [record](./record.mdx) type
5289+
5290+
5291+
5292+
5293+
5294+## Constructor Arguments
5295+
5296+A variant's constructors can hold extra data separated by comma.
5297+
5298+
5299+
5300+Here, `Instagram` holds a `string`, and `Facebook` holds a `string` and an `int`. Usage:
5301+
5302+
5303+
5304+### Labeled Variant Payloads (Inline Record)
5305+
5306+If a variant payload has multiple fields, you can use a record-like syntax to label them for better readability:
5307+
5308+
5309+
5310+This is technically called an "inline record", and only allowed within a variant constructor. You cannot inline a record type declaration anywhere else in ReScript.
5311+
5312+Of course, you can just put a regular record type in a variant too:
5313+
5314+
5315+
5316+The output is slightly uglier and less performant than the former.
5317+
5318+## Variant Type Spreads
5319+
5320+Just like [with records](./record.mdx#record-type-spread), it's possible to use type spreads to create new variants from other variants:
5321+
5322+
5323+
5324+Type `b` is now:
5325+
5326+
5327+
5328+Type spreads act as a 'copy-paste', meaning all constructors are copied as-is from `a` to `b`. Here are the rules for spreads to work:
5329+
5330+- You can't overwrite constructors, so the same constructor name can exist in only one place as you spread. This is true even if the constructors are identical.
5331+- All variants and constructors must share the same runtime configuration - `@unboxed`, `@tag`, `@as` and so on.
5332+- You can't spread types in recursive definitions.
5333+
5334+Note that you need a leading `|` if you want to use a spread in the first position of a variant definition.
5335+
5336+### Pattern Matching On Variant
5337+
5338+See the [Pattern Matching/Destructuring](./pattern-matching-destructuring.mdx) section later.
5339+
5340+## JavaScript Output
5341+
5342+A variant value compiles to 3 possible JavaScript outputs depending on its type declaration:
5343+
5344+- If the variant value is a constructor with no payload, it compiles to a string of the constructor name. Example: `Yes` compiles to `"Yes"`.
5345+- If it's a constructor with a payload, it compiles to an object with the field `TAG` and the field `_0` for the first payload, `_1` for the second payload, etc. The value of `TAG` is the constructor name as string by default, but note that the name of the `TAG` field as well as the string value used for each constructor name [can be customized](#tagged-variants).
5346+- Labeled variant payloads (the inline record trick earlier) compile to an object with the label names instead of `_0`, `_1`, etc. The object will have the `TAG` field as per the previous rule.
5347+
5348+Check the output in these examples:
5349+
5350+
5351+
5352+## Tagged variants
5353+
5354+- The `@tag` attribute lets you customize the discriminator (default: `TAG`).
5355+- `@as` attributes control what each variant case is discriminated on (default: the variant case name as string).
5356+
5357+### Example: Binding to TypeScript enums
5358+
5359+
5360+
5361+You can bind to the above enums like so:
5362+
5363+
5364+
5365+Now, this maps 100% to the TypeScript code, including letting us bring over the documentation strings so we get a nice editor experience.
5366+
5367+### String literals
5368+
5369+The same logic is easily applied to string literals from TypeScript, only here the benefit is even larger, because string literals have the same limitations in TypeScript that polymorphic variants have in ReScript:
5370+
5371+
5372+
5373+There's no way to attach documentation strings to string literals in TypeScript, and you only get the actual value to interact with.
5374+
5375+### Valid `@as` payloads
5376+
5377+Here's a list of everything you can put in the `@as` tag of a variant constructor:
5378+
5379+- A string literal: `@as("success")`
5380+- An int: `@as(5)`
5381+- A float: `@as(1.5)`
5382+- True/false: `@as(true)` and `@as(false)`
5383+- Null: `@as(null)`
5384+- Undefined: `@as(undefined)`
5385+
5386+## Untagged variants
5387+
5388+With _untagged variants_ it is possible to mix types together that normally can't be mixed in the ReScript type system, as long as there's a way to discriminate them at runtime. For example, with untagged variants you can represent a heterogenous array:
5389+
5390+
5391+
5392+Here, each value will be _unboxed_ at runtime. That means that the variant payload will be all that's left, the variant case name wrapping the payload itself will be stripped out and the payload will be all that remains.
5393+
5394+It, therefore, compiles to this JS:
5395+
5396+
5397+
5398+In the above example, reaching back into the values is as simple as pattern matching on them.
5399+
5400+### Advanced: Unboxing rules
5401+
5402+#### No overlap in constructors
5403+
5404+A variant can be unboxed if no constructors have overlap in their runtime representation.
5405+
5406+For example, you can't have `String1(string) | String2(string)` in the same unboxed variant, because there's no way for ReScript to know at runtime which of `String1` or `String2` that `string` belongs to, as it could belong to both.
5407+The same goes for two records - even if they have fully different shapes, they're still JavaScript `object` at runtime.
5408+
5409+Don't worry - the compiler will guide you and ensure there's no overlap.
5410+
5411+#### What you can unbox
5412+
5413+Here's a list of all possible things you can unbox:
5414+
5415+- `string`: `String(string)`
5416+- `float`: `Float(float)`. Note you can only have one of `float` or `int` because JavaScript only has `number` (not actually `int` and `float` like in ReScript) so we can't disambiguate between `float` and `int` at runtime.
5417+- `int`: `Int(int)`. See note above on `float`.
5418+- `bigint`: `BigInt(int)`. **Since 11.1** This is a distinct type from JavaScript's `number` type so you can use it beside either `float` or `int`.
5419+- `bool`: `Boolean(bool)`
5420+- `array<'value>`: `List(array<string>)`
5421+- `('a, 'b, 'c)`: `Tuple((string, int, bool))`. Any size of tuples works, but you can have only one case of array or tuple in a variant.
5422+- `promise<'value>`: `Promise(promise<string>)`
5423+- `Dict.t`: `Object(Dict.t<string>)`
5424+- `Date.t`: `Date(Date.t)`. A JavaScript date.
5425+- `Blob.t`: `Blob(Blob.t)`. A JavaScript blob.
5426+- `File.t`: `File(File.t)`. A JavaScript file.
5427+- `RegExp.t`: `RegExp(RegExp.t)`. A JavaScript regexp instance.
5428+
5429+Again notice that the constructor names can be anything, what matters is what's in the payload.
5430+
5431+> **Under the hood**: Untagged variants uses a combination of JavaScript `typeof` and `instanceof` checks to discern between unboxed constructors at runtime. This means that we could add more things to the list above detailing what can be unboxed, if there are useful enough use cases.
5432+
5433+### Pattern matching on unboxed variants
5434+
5435+Pattern matching works the same on unboxed variants as it does on regular variants. In fact, in the perspective of ReScript's type system there's no difference between untagged and tagged variants. You can do virtually the same things with both. That's the beauty of untagged variants - they're just variants to you as a developer.
5436+
5437+Here's an example of pattern matching on an unboxed nullable value that illustrates the above:
5438+
5439+
5440+
5441+No difference to how you'd do with a regular variant. But, the runtime representation is different to a regular variant.
5442+
5443+> Notice how `@as` allows us to say that an untagged variant case should map to a specific underlying _primitive_. `Present` has a type variable, so it can hold any type. And since it's an unboxed type, only the payloads `'a` or `null` will be kept at runtime. That's where the magic comes from.
5444+
5445+### Decoding and encoding JSON idiomatically
5446+
5447+With untagged variants, we have everything we need to define a native JSON type:
5448+
5449+
5450+
5451+Here's an example of how you could write your own JSON decoders easily using the above, leveraging pattern matching:
5452+
5453+
5454+
5455+Encoding that same structure back into JSON is also easy:
5456+
5457+
5458+
5459+This can be extrapolated to many more cases.
5460+
5461+### Advanced: Catch-all Constructors
5462+
5463+With untagged variants comes a rather interesting capability - catch-all cases are now possible to encode directly into a variant.
5464+
5465+Let's look at how it works. Imagine you're using a third party API that returns a list of available animals. You could of course model it as a regular `string`, but given that variants can be used as "typed strings", using a variant would give you much more benefit:
5466+
5467+
5468+
5469+This is all fine and good as long as the API returns `"Dog"`, `"Cat"` or `"Bird"` for `animal`.
5470+However, what if the API changes before you have a chance to deploy new code, and can now return `"Turtle"` as well? Your code would break down because the variant `animal` doesn't cover `"Turtle"`.
5471+
5472+So, we'll need to go back to `string`, loosing all of the goodies of using a variant, and then do manual conversion into the `animal` variant from `string`, right?
5473+Well, this used to be the case before, but not anymore! We can leverage untagged variants to bake in handling of unknown values into the variant itself.
5474+
5475+Let's update our type definition first:
5476+
5477+
5478+
5479+Notice we've added `@unboxed` and the constructor `UnknownAnimal(string)`. Remember how untagged variants work? You remove the constructors and just leave the payloads. This means that the variant above at runtime translates to this (made up) JavaScript type:
5480+
5481+```
5482+type animal = "Dog" | "Cat" | "Bird" | string
5483+```
5484+
5485+So, any string not mapping directly to one of the payloadless constructors will now map to the general `string` case.
5486+
5487+As soon as we've added this, the compiler complains that we now need to handle this additional case in our pattern match as well. Let's fix that:
5488+
5489+
5490+
5491+There! Now the external API can change as much as it wants, we'll be forced to write all code that interfaces with `animal` in a safe way that handles all possible cases. All of this baked into the variant definition itself, so no need for labor intensive manual conversion.
5492+
5493+This is useful in any scenario when you use something enum-style that's external and might change. Additionally, it's also useful when something external has a large number of possible values that are known, but where you only care about a subset of them. With a catch-all case you don't need to bind to all of them just because they can happen, you can safely just bind to the ones you care about and let the catch-all case handle the rest.
5494+
5495+## Coercion
5496+
5497+In certain situations, variants can be coerced to other variants, or to and from primitives. Coercion is always zero cost.
5498+
5499+### Coercing Variants to Other Variants
5500+
5501+You can coerce a variant to another variant if they're identical in runtime representation, and additionally if the variant you're coercing can be represented as the variant you're coercing to.
5502+
5503+Here's an example using [variant type spreads](#variant-type-spreads):
5504+
5505+
5506+
5507+### Coercing Variants to Primitives
5508+
5509+Variants that are guaranteed to always be represented by a single primitive at runtime can be coerced to that primitive.
5510+
5511+It works with strings, the default runtime representation of payloadless constructors:
5512+
5513+
5514+
5515+If you were to configure all of your constructors to be represented as `int` or `float`, you could coerce to those too:
5516+
5517+
5518+
5519+### Advanced: Coercing `string` to Variant
5520+
5521+In certain situations it's possible to coerce a `string` to a variant. This is an advanced technique that you're unlikely to need much, but when you do it's really useful.
5522+
5523+You can coerce a `string` to a variant when:
5524+
5525+- Your variant is `@unboxed`
5526+- Your variant has a "catch-all" `string` case
5527+
5528+Let's look at an example:
5529+
5530+
5531+
5532+This works because the variant is unboxed **and** has a catch-all case. So, if you throw a string at this variant that's not representable by the payloadless constructors, like `"One"` or `"Two"`, it'll _always_ end up in `Other(string)`, since that case can represent any `string`.
5533+
5534+## Tips & Tricks
5535+
5536+**Be careful** not to confuse a constructor carrying 2 arguments with a constructor carrying a single tuple argument:
5537+
5538+
5539+
5540+### Variants Must Have Constructors
5541+
5542+If you come from an untyped language, you might be tempted to try `type myType = int | string`. This isn't possible in ReScript; you'd have to give each branch a constructor: `type myType = Int(int) | String(string)`. The former looks nice, but causes lots of trouble down the line.
5543+
5544+### Interop with JavaScript
5545+
5546+_This section assumes knowledge about our JavaScript interop. Skip this if you haven't felt the itch to use variants for wrapping JS functions yet_.
5547+
5548+Quite a few JS libraries use functions that can accept many types of arguments. In these cases, it's very tempting to model them as variants. For example, suppose there's a `myLibrary.draw` JS function that takes in either a `number` or a `string`. You might be tempted to bind it like so:
5549+
5550+
5551+
5552+**Try not to do that**, as this generates extra noisy output. Instead, use the `@unboxed` attribute to guide ReScript to generate more efficient code:
5553+
5554+
5555+
5556+Alternatively, define two `external`s that both compile to the same JS call:
5557+
5558+
5559+
5560+ReScript also provides [a few other ways](./bind-to-js-function.mdx#modeling-polymorphic-function) to do this.
5561+
5562+### Variant Types Are Found By Field Name
5563+
5564+Please refer to this [record section](./record.mdx#tips--tricks). Variants are the same: a function can't accept an arbitrary constructor shared by two different variants. Again, such feature exists; it's called a polymorphic variant. We'll talk about this in the future =).
5565+
5566+## Design Decisions
5567+
5568+Variants, in their many forms (polymorphic variant, open variant, GADT, etc.), are likely _the_ feature of a type system such as ReScript's. The aforementioned `option` variant, for example, obliterates the need for nullable types, a major source of bugs in other languages. Philosophically speaking, a problem is composed of many possible branches/conditions. Mishandling these conditions is the majority of what we call bugs. **A type system doesn't magically eliminate bugs; it points out the unhandled conditions and asks you to cover them**\*. The ability to model "this or that" correctly is crucial.
5569+
5570+For example, some folks wonder how the type system can safely eliminate badly formatted JSON data from propagating into their program. They don't, not by themselves! But if the parser returns the `option` type `None | Some(actualData)`, then you'd have to handle the `None` case explicitly in later call sites. That's all there is.
5571+
5572+Performance-wise, a variant can potentially tremendously speed up your program's logic. Here's a piece of JavaScript:
5573+
5574+
5575+
5576+There's a linear amount of branch checking here (`O(n)`). Compare this to using a ReScript variant:
5577+
5578+
5579+
5580+The compiler sees the variant, then
5581+
5582+1. conceptually turns them into `type animal = "Dog" | "Cat" | "Bird"`
5583+2. compiles `switch` to a constant-time jump table (`O(1)`).
5584+# Warning Numbers
5585+
5586+You can configure which warnings the ReScript compiler generates
5587+[in the build configuration](./build-configuration.mdx#warnings) or
5588+using the [`@warning()`](../../syntax-lookup/decorator_expression_warning.mdx) or the [`@@warning()`](../../syntax-lookup/decorator_module_warning.mdx) decorator.
5589+
5590+<WarningTable />
+480,
-0
1@@ -0,0 +1,480 @@
2+---
3+name: working-with-bug
4+description: Use when collaborating with humans using the bug CLI tool to track and resolve issues
5+---
6+
7+# Bug CLI Agent Collaboration
8+
9+## Overview
10+
11+The `bug` CLI tool provides a dual API for issue tracking:
12+- **Human API** (`bug new`, `bug read`, etc.): Lenient, interactive, designed for human use
13+- **Agent API** (`bug agent new`, `bug agent read`, etc.): Strict, non-interactive, designed for automation
14+
15+**Core principle:** Always use commands under `bug agent` when acting as an agent. These commands are non-interactive, require explicit flags, and use the agent identity created during `bug init`.
16+
17+**Announce at start:** "I'm using the bug-cli-agent skill to collaborate on this issue."
18+
19+## Typical Collaboration Workflow
20+
21+When a user asks you to work on a bug, follow this workflow:
22+
23+### Step 1: Read the Bug
24+
25+Use `bug agent read [bugID]` to fetch the bug details and all existing comments (which may include a previously documented plan):
26+
27+```bash
28+bug agent read abc1234
29+```
30+
31+**Important:** Use `bug agent read`, not `bug read`. The agent version is non-interactive and returns structured output suitable for parsing.
32+
33+### Step 2: Create an Implementation Plan
34+
35+**REQUIRED SUB-SKILL:** Invoke `superpowers:writing-plans` to create a comprehensive implementation plan.
36+
37+```
38+Announce: "I'm using superpowers:writing-plans to create an implementation plan."
39+```
40+
41+This will generate a detailed, bite-sized plan for resolving the bug.
42+
43+### Step 3: Document the Plan as a Comment
44+
45+Save the plan to the bug by adding it as a comment. Plans should be written in raw markdown format:
46+
47+```bash
48+bug agent comment abc1234 --message "## Implementation Plan
49+
50+### Task 1: [Component Name]
51+**Files:**
52+- Create: path/to/file.ts
53+- Test: path/to/test.ts
54+
55+**Step 1: Write the failing test**
56+[code example]
57+
58+**Step 2: Run test to verify it fails**
59+Run: command
60+Expected: output"
61+```
62+
63+For multi-line plans, the message flag accepts the full markdown content.
64+
65+### Step 4: Execute the Plan
66+
67+When ready to implement:
68+
69+1. **Read the bug again** to get the plan from the comments:
70+ ```bash
71+ bug agent read abc1234
72+ ```
73+
74+2. **REQUIRED SUB-SKILL:** Invoke `superpowers:executing-plans` to execute the plan task-by-task:
75+ ```
76+ Announce: "I'm using superpowers:executing-plans to implement the documented plan."
77+ ```
78+
79+3. **Update the bug** when work is complete with a summary of what was done using `bug agent comment`.
80+
81+4. **Do not close the bug** until the user checks the implementation and tells you to do so. Then use:
82+ ```bash
83+ bug agent close abc1234
84+ ```
85+
86+## Agent API Reference
87+
88+All agent commands are non-interactive and require explicit flags. They use the agent identity (name: "agent", created during `bug init`).
89+
90+### bug agent read [bugID]
91+
92+Display a bug/issue and all its comments.
93+
94+```bash
95+bug agent read abc1234
96+```
97+
98+**Output includes:**
99+- Title, Author, Creation date, Status, Labels
100+- Description (first comment)
101+- All additional comments with their IDs
102+
103+**Use this to:**
104+- Fetch bug details for analysis
105+- Retrieve documented plans from comments
106+- Check current status before acting
107+
108+### bug agent new --title "..." [--message "..." | --stdin | --from-file <path>]
109+
110+Create a new bug/issue as the agent.
111+
112+```bash
113+# Using --message flag (simple strings)
114+bug agent new --title "CI Failure" --message "Build failed on commit abc123"
115+
116+# Using --stdin (pipe content)
117+echo "Build failed on commit abc123" | bug agent new --title "CI Failure" --stdin
118+
119+# Using --from-file (read from file)
120+bug agent new --title "CI Failure" --from-file /tmp/description.md
121+```
122+
123+**Required flags:**
124+- `--title`: Issue title
125+- One of the following for message content:
126+ - `--message "..."`: Provide message as a command-line string
127+ - `--stdin`: Read message from standard input
128+ - `--from-file <path>`: Read message from a file
129+
130+**Important:** `--message`, `--stdin`, and `--from-file` are **mutually exclusive**. You must choose exactly one method to provide the message content.
131+
132+**Best practice for multi-line markdown content:** Use `--stdin` or `--from-file` instead of `--message`. Long multi-line strings with markdown formatting often fail when passed as shell command-line arguments due to escaping issues.
133+
134+**Examples with HEREDOC and temp files:**
135+
136+```bash
137+# Using HEREDOC with --stdin
138+bug agent new --title "Complex Bug" --stdin << 'EOF'
139+## Description
140+
141+This bug involves multiple steps:
142+1. First step
143+2. Second step
144+
145+**Expected:** It should work
146+**Actual:** It fails with error
147+EOF
148+
149+# Using a temp file for large content
150+cat > /tmp/bug_desc.md << 'EOF'
151+## Problem
152+Detailed markdown content here...
153+
154+- List item 1
155+- List item 2
156+EOF
157+bug agent new --title "Complex Bug" --from-file /tmp/bug_desc.md
158+```
159+
160+### bug agent comment [bugID] [--message "..." | --stdin | --from-file <path>]
161+
162+Add a comment to an existing bug.
163+
164+```bash
165+# Using --message flag (simple strings)
166+bug agent comment abc1234 --message "Automated analysis complete"
167+
168+# Using --stdin (pipe content)
169+echo "Analysis complete" | bug agent comment abc1234 --stdin
170+
171+# Using --from-file (read from file)
172+bug agent comment abc1234 --from-file /tmp/comment.md
173+```
174+
175+**Required:** Exactly one of the following for message content:
176+- `--message "..."`: Provide message as a command-line string
177+- `--stdin`: Read message from standard input
178+- `--from-file <path>`: Read message from a file
179+
180+**Important:** `--message`, `--stdin`, and `--from-file` are **mutually exclusive**. You must choose exactly one method to provide the message content.
181+
182+**Best practice for multi-line markdown content:** Use `--stdin` or `--from-file` instead of `--message`. Long multi-line strings with markdown formatting often fail when passed as shell command-line arguments due to escaping issues.
183+
184+**Examples with HEREDOC and temp files:**
185+
186+```bash
187+# Using HEREDOC with --stdin
188+bug agent comment abc1234 --stdin << 'EOF'
189+## Implementation Plan
190+
191+### Task 1: [Component Name]
192+**Files:**
193+- Create: path/to/file.ts
194+
195+**Step 1: Write the failing test**
196+[code example]
197+EOF
198+
199+# Using a temp file for large content
200+cat > /tmp/progress.md << 'EOF'
201+## Progress Update
202+
203+Completed the following:
204+- Item 1
205+- Item 2
206+EOF
207+bug agent comment abc1234 --from-file /tmp/progress.md
208+```
209+
210+**Use this to:**
211+- Document implementation plans
212+- Add progress updates
213+- Record findings or analysis results
214+
215+### bug agent edit [bugID] --title "..." [--message "..." | --stdin | --from-file <path>]
216+
217+Edit an issue's title and/or description.
218+
219+```bash
220+# Edit title only
221+bug agent edit abc1234 --title "New Title"
222+
223+# Edit message using --message flag (simple strings)
224+bug agent edit abc1234 --message "New description"
225+
226+# Edit message using --stdin
227+echo "New description" | bug agent edit abc1234 --stdin
228+
229+# Edit message using --from-file
230+bug agent edit abc1234 --from-file /tmp/new_desc.md
231+
232+# Edit both title and message
233+bug agent edit abc1234 --title "New Title" --message "New description"
234+```
235+
236+**Flags:**
237+- `--title`: New issue title (optional, but at least one flag must be provided)
238+- One of the following for message content (optional):
239+ - `--message "..."`: Provide message as a command-line string
240+ - `--stdin`: Read message from standard input
241+ - `--from-file <path>`: Read message from a file
242+
243+**Important:** When editing the message, `--message`, `--stdin`, and `--from-file` are **mutually exclusive**. You must choose exactly one method to provide the message content.
244+
245+**Best practice for multi-line markdown content:** Use `--stdin` or `--from-file` instead of `--message`. Long multi-line strings with markdown formatting often fail when passed as shell command-line arguments due to escaping issues.
246+
247+**Examples with HEREDOC:**
248+
249+```bash
250+# Update description with HEREDOC
251+bug agent edit abc1234 --stdin << 'EOF'
252+## Updated Description
253+
254+New details about this bug:
255+- Point 1
256+- Point 2
257+EOF
258+```
259+
260+**Note:** When editing bugs, at least one of `--title` or a message option must be provided.
261+
262+### bug agent edit [commentID] [--message "..." | --stdin | --from-file <path>]
263+
264+Edit an existing comment.
265+
266+```bash
267+# Using --message flag (simple strings)
268+bug agent edit def5678 --message "Updated comment text"
269+
270+# Using --stdin (pipe content)
271+echo "Updated comment text" | bug agent edit def5678 --stdin
272+
273+# Using --from-file (read from file)
274+bug agent edit def5678 --from-file /tmp/updated_comment.md
275+```
276+
277+**Required:** Exactly one of the following for message content:
278+- `--message "..."`: Provide message as a command-line string
279+- `--stdin`: Read message from standard input
280+- `--from-file <path>`: Read message from a file
281+
282+**Important:**
283+- Comments have no title field. Only message options are accepted when editing a comment ID.
284+- `--message`, `--stdin`, and `--from-file` are **mutually exclusive**. You must choose exactly one method to provide the message content.
285+
286+**Best practice for multi-line markdown content:** Use `--stdin` or `--from-file` instead of `--message`. Long multi-line strings with markdown formatting often fail when passed as shell command-line arguments due to escaping issues.
287+
288+**Examples with HEREDOC:**
289+
290+```bash
291+# Update comment with HEREDOC
292+bug agent edit def5678 --stdin << 'EOF'
293+## Updated Analysis
294+
295+New findings:
296+- Finding 1
297+- Finding 2
298+EOF
299+```
300+
301+### bug agent open [bugID]
302+
303+Open a closed bug/issue.
304+
305+```bash
306+bug agent open abc1234
307+```
308+
309+### bug agent close [bugID]
310+
311+Close an open bug/issue.
312+
313+```bash
314+bug agent close abc1234
315+```
316+
317+Use this when the issue is resolved.
318+
319+### bug agent rm [bugID]
320+
321+Remove a bug/issue.
322+
323+```bash
324+bug agent rm abc1234
325+bug agent remove abc1234
326+```
327+
328+**WARNING: This action is permanent.**
329+
330+**Note:** Individual comments cannot be removed. Use this to remove the entire issue.
331+
332+## Important Notes
333+
334+### Agent Identity
335+
336+The agent identity is created during `bug init` with:
337+- Name: "agent"
338+- Email: "" (empty)
339+
340+All `bug agent` commands use this identity. Do not attempt to create or modify the agent identity.
341+
342+### ID Formats
343+
344+Bug IDs are 64-character hex strings. The CLI accepts shortened prefixes:
345+- **Short ID**: First 7 characters (e.g., `abc1234`)
346+- **Full ID**: Complete 64-character ID
347+
348+Both formats work with all commands. Short IDs are preferred for convenience.
349+
350+### Working with a Repository in a Different Location
351+
352+All commands accept a `--repo` flag:
353+```bash
354+bug agent --repo /path/to/repo read abc1234
355+bug agent --repo /path/to/repo comment abc1234 --message "Update"
356+```
357+
358+By default, commands operate on the current directory (`.`).
359+
360+### Comment IDs vs Bug IDs
361+
362+When editing:
363+- **Bug IDs** (e.g., `abc1234`) refer to the entire issue
364+- **Comment IDs** (e.g., `def5678`) refer to individual comments
365+
366+The `bug agent edit` command automatically detects the type and behaves accordingly:
367+- For bugs: accepts `--title` and/or `--message`
368+- For comments: accepts only `--message`
369+
370+### Message Content Options
371+
372+Agent commands that require message content (`bug agent new`, `bug agent comment`, `bug agent edit`) support three mutually exclusive methods for providing the message:
373+
374+| Option | When to Use | Example |
375+|--------|-------------|---------|
376+| `--message "..."` | Short, simple text without special characters | `bug agent new --title "Bug" --message "It broke"` |
377+| `--stdin` | Multi-line content, markdown, or piped input | `cat description.md \| bug agent new --title "Bug" --stdin` |
378+| `--from-file <path>` | Large content already in a file | `bug agent new --title "Bug" --from-file /tmp/desc.md` |
379+
380+**Important rules:**
381+1. **Mutually exclusive:** You must use exactly one of `--message`, `--stdin`, or `--from-file` per command
382+2. **Best practice for markdown:** Use `--stdin` or `--from-file` for multi-line markdown content to avoid shell escaping issues
383+3. **Error handling:** If you specify multiple options, the command will fail with a clear error message explaining the conflict
384+
385+**HEREDOC patterns (recommended for agents):**
386+
387+```bash
388+# Pattern 1: Inline HEREDOC to stdin
389+bug agent comment abc1234 --stdin << 'EOF'
390+## Implementation Plan
391+
392+### Task 1
393+- Step 1
394+- Step 2
395+EOF
396+
397+# Pattern 2: Write to temp file first
398+plan_file=$(mktemp)
399+cat > "$plan_file" << 'EOF'
400+## Implementation Plan
401+
402+### Task 1
403+- Step 1
404+- Step 2
405+EOF
406+bug agent comment abc1234 --from-file "$plan_file"
407+rm "$plan_file"
408+```
409+
410+## Complete Workflow Example
411+
412+**Scenario:** User asks "Can you fix the bug with ID abc1234?"
413+
414+```bash
415+# Step 1: Read the bug
416+bug agent read abc1234
417+
418+# Output shows:
419+# Title: Memory leak in data processor
420+# Author: [email protected]
421+# Status: open
422+# Description: The data processor leaks memory when processing large files...
423+
424+# Step 2: Invoke writing-plans skill
425+Announce: "I'm using superpowers:writing-plans to create an implementation plan."
426+
427+# Step 3: Document the plan as a comment
428+bug agent comment abc1234 --message "## Fix: Memory leak in data processor
429+
430+### Task 1: Add failing test
431+**Files:**
432+- Create: test/memory_test.go
433+- Test: TestMemoryLeak
434+
435+**Step 1: Write failing test**
436+[code]
437+
438+**Step 2: Verify test fails**
439+Run: go test -v ./test
440+Expected: FAIL: memory leak detected
441+
442+### Task 2: Implement fix
443+..."
444+
445+# Step 4: When ready to execute, read the bug again
446+bug agent read abc1234
447+
448+# Step 5: Invoke executing-plans skill
449+Announce: "I'm using superpowers:executing-plans to implement the documented plan."
450+
451+# Step 6: Add progress comments as needed
452+bug agent comment abc1234 --message "Task 1 complete: Added failing test in commit abc1234"
453+
454+# Step 7: Close the bug when complete
455+bug agent close abc1234
456+```
457+
458+## Integration with Superpowers Skills
459+
460+**REQUIRED SUB-SKILLS:**
461+
462+- **superpowers:writing-plans** - REQUIRED for creating implementation plans
463+ - Creates bite-sized, detailed tasks
464+ - Documents exact files, code, and verification steps
465+ - Use when analyzing a bug before implementing
466+
467+- **superpowers:executing-plans** - REQUIRED for implementing documented plans
468+ - Executes tasks in batches with review checkpoints
469+ - Follows the plan exactly as documented in bug comments
470+ - Use when implementing a plan previously documented on a bug
471+
472+## Error Handling
473+
474+If a command fails:
475+
476+1. **Read the error message** - it includes guidance on what to do next
477+2. **Common issues:**
478+ - "agent identity not found" → Run `bug init` first
479+ - "failed to resolve bug ID" → Check the ID is correct
480+ - "title/message cannot be empty" → Ensure required flags are provided
481+3. **Use `bug agent read`** to verify the current state before retrying
+150,
-0
1@@ -0,0 +1,150 @@
2+---
3+name: writing-plans
4+description: Use when you have a spec or requirements for a multi-step task, before touching code
5+---
6+
7+# Writing Plans
8+
9+## Overview
10+
11+Write comprehensive implementation plans assuming the engineer has zero context for our codebase and questionable taste. Document everything they need to know: which files to touch for each task, code, testing, docs they might need to check, how to test it. Give them the whole plan as bite-sized tasks. DRY. YAGNI. TDD. Frequent commits.
12+
13+Assume they are a skilled developer, but know almost nothing about our toolset or problem domain. Assume they don't know good test design very well.
14+
15+**Announce at start:** "I'm using the writing-plans skill to create the implementation plan."
16+
17+**Context:** This should be run in a dedicated worktree (created by brainstorming skill).
18+
19+**Save plans:** Use required skill **`working-with-bug`** when collaborating with the user on a bug-enabled code base. Save the plan document as a comment on the bug - **do not save the plan in a file**. Only use a file at `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md` to record your plan if you are not working with the `bug` tracking system.
20+
21+## Scope Check
22+
23+If the spec covers multiple independent subsystems, it should have been broken into sub-project specs during brainstorming. If it wasn't, suggest breaking this into separate plans — one per subsystem. Each plan should produce working, testable software on its own.
24+
25+## File Structure
26+
27+Before defining tasks, map out which files will be created or modified and what each one is responsible for. This is where decomposition decisions get locked in.
28+
29+- Design units with clear boundaries and well-defined interfaces. Each file should have one clear responsibility.
30+- You reason best about code you can hold in context at once, and your edits are more reliable when files are focused. Prefer smaller, focused files over large ones that do too much.
31+- Files that change together should live together. Split by responsibility, not by technical layer.
32+- In existing codebases, follow established patterns. If the codebase uses large files, don't unilaterally restructure - but if a file you're modifying has grown unwieldy, including a split in the plan is reasonable.
33+
34+This structure informs the task decomposition. Each task should produce self-contained changes that make sense independently.
35+
36+## Bite-Sized Task Granularity
37+
38+**Each step is one action (2-5 minutes):**
39+- "Write the failing test" - step
40+- "Run it to make sure it fails" - step
41+- "Implement the minimal code to make the test pass" - step
42+- "Run the tests and make sure they pass" - step
43+- "Commit" - step
44+
45+## Plan Document Header
46+
47+**Every plan MUST start with this header:**
48+
49+```markdown
50+# [Feature Name] Implementation Plan
51+
52+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
53+
54+**Goal:** [One sentence describing what this builds]
55+
56+**Architecture:** [2-3 sentences about approach]
57+
58+**Tech Stack:** [Key technologies/libraries]
59+
60+---
61+```
62+
63+## Task Structure
64+
65+````markdown
66+### Task N: [Component Name]
67+
68+**Files:**
69+- Create: `exact/path/to/file.py`
70+- Modify: `exact/path/to/existing.py:123-145`
71+- Test: `tests/exact/path/to/test.py`
72+
73+- [ ] **Step 1: Write the failing test**
74+
75+```python
76+def test_specific_behavior():
77+ result = function(input)
78+ assert result == expected
79+```
80+
81+- [ ] **Step 2: Run test to verify it fails**
82+
83+Run: `pytest tests/path/test.py::test_name -v`
84+Expected: FAIL with "function not defined"
85+
86+- [ ] **Step 3: Write minimal implementation**
87+
88+```python
89+def function(input):
90+ return expected
91+```
92+
93+- [ ] **Step 4: Run test to verify it passes**
94+
95+Run: `pytest tests/path/test.py::test_name -v`
96+Expected: PASS
97+
98+- [ ] **Step 5: Commit**
99+
100+```bash
101+jj commit -m "feat: add specific feature" tests/path/test.py src/path/file.py
102+```
103+````
104+
105+## No Placeholders
106+
107+Every step must contain the actual content an engineer needs. These are **plan failures** — never write them:
108+- "TBD", "TODO", "implement later", "fill in details"
109+- "Add appropriate error handling" / "add validation" / "handle edge cases"
110+- "Write tests for the above" (without actual test code)
111+- "Similar to Task N" (repeat the code — the engineer may be reading tasks out of order)
112+- Steps that describe what to do without showing how (code blocks required for code steps)
113+- References to types, functions, or methods not defined in any task
114+
115+## Remember
116+- Exact file paths always
117+- Complete code in every step — if a step changes code, show the code
118+- Exact commands with expected output
119+- DRY, YAGNI, TDD, frequent commits
120+
121+## Self-Review
122+
123+After writing the complete plan, look at the spec with fresh eyes and check the plan against it. This is a checklist you run yourself — not a subagent dispatch.
124+
125+**1. Spec coverage:** Skim each section/requirement in the spec. Can you point to a task that implements it? List any gaps.
126+
127+**2. Placeholder scan:** Search your plan for red flags — any of the patterns from the "No Placeholders" section above. Fix them.
128+
129+**3. Type consistency:** Do the types, method signatures, and property names you used in later tasks match what you defined in earlier tasks? A function called `clearLayers()` in Task 3 but `clearFullLayers()` in Task 7 is a bug.
130+
131+If you find issues, fix them inline. No need to re-review — just fix and move on. If you find a spec requirement with no task, add the task.
132+
133+## Execution Handoff
134+
135+After saving the plan, offer execution choice:
136+
137+**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Two execution options:**
138+
139+**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
140+
141+**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
142+
143+**Which approach?"**
144+
145+**If Subagent-Driven chosen:**
146+- **REQUIRED SUB-SKILL:** Use superpowers:subagent-driven-development
147+- Fresh subagent per task + two-stage review
148+
149+**If Inline Execution chosen:**
150+- **REQUIRED SUB-SKILL:** Use superpowers:executing-plans
151+- Batch execution with checkpoints for review
1@@ -0,0 +1,49 @@
2+# Plan Document Reviewer Prompt Template
3+
4+Use this template when dispatching a plan document reviewer subagent.
5+
6+**Purpose:** Verify the plan is complete, matches the spec, and has proper task decomposition.
7+
8+**Dispatch after:** The complete plan is written.
9+
10+```
11+Task tool (general-purpose):
12+ description: "Review plan document"
13+ prompt: |
14+ You are a plan document reviewer. Verify this plan is complete and ready for implementation.
15+
16+ **Plan to review:** [PLAN_FILE_PATH]
17+ **Spec for reference:** [SPEC_FILE_PATH]
18+
19+ ## What to Check
20+
21+ | Category | What to Look For |
22+ |----------|------------------|
23+ | Completeness | TODOs, placeholders, incomplete tasks, missing steps |
24+ | Spec Alignment | Plan covers spec requirements, no major scope creep |
25+ | Task Decomposition | Tasks have clear boundaries, steps are actionable |
26+ | Buildability | Could an engineer follow this plan without getting stuck? |
27+
28+ ## Calibration
29+
30+ **Only flag issues that would cause real problems during implementation.**
31+ An implementer building the wrong thing or getting stuck is an issue.
32+ Minor wording, stylistic preferences, and "nice to have" suggestions are not.
33+
34+ Approve unless there are serious gaps — missing requirements from the spec,
35+ contradictory steps, placeholder content, or tasks so vague they can't be acted on.
36+
37+ ## Output Format
38+
39+ ## Plan Review
40+
41+ **Status:** Approved | Issues Found
42+
43+ **Issues (if any):**
44+ - [Task X, Step Y]: [specific issue] - [why it matters for implementation]
45+
46+ **Recommendations (advisory, do not block approval):**
47+ - [suggestions for improvement]
48+```
49+
50+**Reviewer returns:** Status, Issues (if any), Recommendations
+863,
-0
1@@ -0,0 +1,863 @@
2+---
3+name: tailwind-css-patterns
4+description: Provides comprehensive Tailwind CSS utility-first styling patterns including responsive design, layout utilities, flexbox, grid, spacing, typography, colors, and modern CSS best practices. Use when styling React/Vue/Svelte components, building responsive layouts, implementing design systems, or optimizing CSS workflow.
5+allowed-tools: Read, Write, Edit, Glob, Grep, Bash
6+---
7+
8+# Tailwind CSS Development Patterns
9+
10+## Overview
11+
12+Expert guide for building modern, responsive user interfaces with Tailwind CSS utility-first framework. Covers v4.1+ features including CSS-first configuration, custom utilities, and enhanced developer experience.
13+
14+## When to Use
15+
16+- Styling React/HTML components with utility classes
17+- Building responsive layouts with breakpoints
18+- Implementing flexbox and grid layouts
19+- Managing spacing, colors, and typography
20+- Creating custom design systems
21+- Optimizing for mobile-first design
22+- Building dark mode interfaces
23+
24+## Instructions
25+
26+1. **Start Mobile-First**: Write base styles for mobile, add responsive prefixes for larger screens
27+2. **Use Design Tokens**: Leverage Tailwind's spacing, color, and typography scales
28+3. **Compose Utilities**: Combine multiple utilities for complex styles
29+4. **Extract Components**: Create reusable component classes for repeated patterns
30+5. **Configure Theme**: Customize design tokens in tailwind.config.js
31+6. **Optimize for Production**: Ensure content paths are configured for CSS purging
32+7. **Test Responsive**: Verify layouts at all breakpoint sizes
33+
34+## Examples
35+
36+### Responsive Card Component
37+
38+```tsx
39+function ProductCard({ product }: { product: Product }) {
40+ return (
41+ <div className="bg-white rounded-lg shadow-lg overflow-hidden
42+ sm:flex sm:max-w-2xl">
43+ <img
44+ className="h-48 w-full object-cover sm:h-auto sm:w-48"
45+ src={product.image}
46+ alt={product.name}
47+ />
48+ <div className="p-6">
49+ <h3 className="text-lg font-semibold text-gray-900">
50+ {product.name}
51+ </h3>
52+ <p className="mt-2 text-gray-600">
53+ {product.description}
54+ </p>
55+ <button className="mt-4 px-4 py-2 bg-indigo-600 text-white
56+ rounded-lg hover:bg-indigo-700 transition">
57+ Add to Cart
58+ </button>
59+ </div>
60+ </div>
61+ );
62+}
63+```
64+
65+## Constraints and Warnings
66+
67+- **Class Proliferation**: Long class strings can reduce readability; extract components when needed
68+- **Purge Configuration**: Must configure content paths correctly for production builds
69+- **Arbitrary Values**: Use sparingly; prefer design tokens for consistency
70+- **Specificity Issues**: Avoid @apply with complex selectors
71+- **Dark Mode**: Requires proper configuration (class or media strategy)
72+- **JIT Mode**: Some dynamic patterns may not be detected; use safelist if needed
73+- **Browser Support**: Check Tailwind docs for browser compatibility
74+
75+## Core Concepts
76+
77+### Utility-First Approach
78+
79+Apply styles directly in markup using utility classes:
80+
81+```html
82+<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
83+ Click me
84+</button>
85+```
86+
87+### Responsive Design
88+
89+Mobile-first breakpoints with prefixes:
90+
91+```html
92+<div class="w-full md:w-1/2 lg:w-1/3">
93+ <!-- Full width on mobile, half on tablet, third on desktop -->
94+</div>
95+```
96+
97+Breakpoint prefixes:
98+- `sm:` - 640px and above
99+- `md:` - 768px and above
100+- `lg:` - 1024px and above
101+- `xl:` - 1280px and above
102+- `2xl:` - 1536px and above
103+
104+## Layout Utilities
105+
106+### Flexbox Layouts
107+
108+Basic flex container:
109+
110+```html
111+<div class="flex items-center justify-between">
112+ <div>Left</div>
113+ <div>Center</div>
114+ <div>Right</div>
115+</div>
116+```
117+
118+Responsive flex direction:
119+
120+```html
121+<div class="flex flex-col md:flex-row gap-4">
122+ <div class="flex-1">Item 1</div>
123+ <div class="flex-1">Item 2</div>
124+ <div class="flex-1">Item 3</div>
125+</div>
126+```
127+
128+Common flex patterns:
129+
130+```html
131+<!-- Center content -->
132+<div class="flex items-center justify-center min-h-screen">
133+ <div>Centered Content</div>
134+</div>
135+
136+<!-- Space between items -->
137+<div class="flex justify-between items-center">
138+ <span>Left</span>
139+ <span>Right</span>
140+</div>
141+
142+<!-- Vertical stack with gap -->
143+<div class="flex flex-col gap-4">
144+ <div>Item 1</div>
145+ <div>Item 2</div>
146+</div>
147+```
148+
149+### Grid Layouts
150+
151+Basic grid:
152+
153+```html
154+<div class="grid grid-cols-3 gap-4">
155+ <div>Column 1</div>
156+ <div>Column 2</div>
157+ <div>Column 3</div>
158+</div>
159+```
160+
161+Responsive grid:
162+
163+```html
164+<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
165+ <!-- 1 column mobile, 2 tablet, 4 desktop -->
166+ <div>Item 1</div>
167+ <div>Item 2</div>
168+ <div>Item 3</div>
169+ <div>Item 4</div>
170+</div>
171+```
172+
173+Auto-fit columns:
174+
175+```html
176+<div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
177+ <!-- Automatically fit columns based on container width -->
178+</div>
179+```
180+
181+### Container & Max Width
182+
183+Centered container with max width:
184+
185+```html
186+<div class="container mx-auto px-4 max-w-7xl">
187+ <!-- Centered content with padding -->
188+</div>
189+```
190+
191+Responsive max width:
192+
193+```html
194+<div class="w-full max-w-md mx-auto">
195+ <!-- Max 448px width, centered -->
196+</div>
197+```
198+
199+## Spacing
200+
201+### Padding & Margin
202+
203+Uniform spacing:
204+
205+```html
206+<div class="p-4">Padding all sides</div>
207+<div class="m-4">Margin all sides</div>
208+```
209+
210+Individual sides:
211+
212+```html
213+<div class="pt-4 pr-8 pb-4 pl-8">
214+ <!-- Top 1rem, Right 2rem, Bottom 1rem, Left 2rem -->
215+</div>
216+```
217+
218+Axis-based spacing:
219+
220+```html
221+<div class="px-4 py-8">
222+ <!-- Horizontal padding 1rem, Vertical padding 2rem -->
223+</div>
224+```
225+
226+Responsive spacing:
227+
228+```html
229+<div class="p-4 md:p-8 lg:p-12">
230+ <!-- Increases padding at larger breakpoints -->
231+</div>
232+```
233+
234+Space between children:
235+
236+```html
237+<div class="space-y-4">
238+ <div>Item 1</div>
239+ <div>Item 2</div>
240+ <div>Item 3</div>
241+</div>
242+```
243+
244+## Typography
245+
246+### Font Size & Weight
247+
248+```html
249+<h1 class="text-4xl font-bold">Large Heading</h1>
250+<h2 class="text-2xl font-semibold">Subheading</h2>
251+<p class="text-base font-normal">Body text</p>
252+<small class="text-sm text-gray-600">Small text</small>
253+```
254+
255+Responsive typography:
256+
257+```html
258+<h1 class="text-2xl md:text-4xl lg:text-6xl font-bold">
259+ Responsive Heading
260+</h1>
261+```
262+
263+### Line Height & Letter Spacing
264+
265+```html
266+<p class="leading-relaxed tracking-wide">
267+ Text with relaxed line height and wide letter spacing
268+</p>
269+```
270+
271+### Text Alignment
272+
273+```html
274+<p class="text-left md:text-center">
275+ Left aligned on mobile, centered on tablet+
276+</p>
277+```
278+
279+## Colors
280+
281+### Background Colors
282+
283+```html
284+<div class="bg-blue-500">Blue background</div>
285+<div class="bg-gray-100">Light gray background</div>
286+<div class="bg-gradient-to-r from-blue-500 to-purple-600">
287+ Gradient background
288+</div>
289+```
290+
291+### Text Colors
292+
293+```html
294+<p class="text-gray-900">Dark text</p>
295+<p class="text-blue-600">Blue text</p>
296+<p class="text-red-500">Error text</p>
297+```
298+
299+### Opacity
300+
301+```html
302+<div class="bg-blue-500 bg-opacity-50">
303+ Semi-transparent blue
304+</div>
305+```
306+
307+## Interactive States
308+
309+### Hover States
310+
311+```html
312+<button class="bg-blue-500 hover:bg-blue-700 transition">
313+ Hover me
314+</button>
315+
316+<a class="text-blue-600 hover:text-blue-800 hover:underline">
317+ Hover link
318+</a>
319+```
320+
321+### Focus States
322+
323+```html
324+<input class="border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 outline-none">
325+```
326+
327+### Active & Disabled States
328+
329+```html
330+<button class="bg-blue-500 active:bg-blue-800 disabled:opacity-50 disabled:cursor-not-allowed">
331+ Button
332+</button>
333+```
334+
335+### Group Hover
336+
337+```html
338+<div class="group">
339+ <img class="group-hover:opacity-75" src="image.jpg" />
340+ <p class="group-hover:text-blue-600">Hover the parent</p>
341+</div>
342+```
343+
344+## Component Patterns
345+
346+### Card Component
347+
348+```html
349+<div class="bg-white rounded-lg shadow-lg overflow-hidden">
350+ <img class="w-full h-48 object-cover" src="image.jpg" alt="Card image" />
351+ <div class="p-6">
352+ <h3 class="text-xl font-bold mb-2">Card Title</h3>
353+ <p class="text-gray-700 mb-4">Card description text goes here.</p>
354+ <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
355+ Action
356+ </button>
357+ </div>
358+</div>
359+```
360+
361+### Responsive User Card
362+
363+```html
364+<div class="max-w-sm mx-auto bg-white rounded-xl shadow-lg overflow-hidden sm:flex sm:max-w-2xl">
365+ <img class="h-48 w-full object-cover sm:h-auto sm:w-48"
366+ src="profile.jpg"
367+ alt="Profile" />
368+ <div class="p-8">
369+ <div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">
370+ Product Engineer
371+ </div>
372+ <h2 class="mt-1 text-xl font-semibold text-gray-900">
373+ John Doe
374+ </h2>
375+ <p class="mt-2 text-gray-500">
376+ Building amazing products with modern technology.
377+ </p>
378+ <button class="mt-4 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition">
379+ Contact
380+ </button>
381+ </div>
382+</div>
383+```
384+
385+### Navigation Bar
386+
387+```html
388+<nav class="bg-white shadow-lg">
389+ <div class="container mx-auto px-4">
390+ <div class="flex justify-between items-center h-16">
391+ <div class="flex items-center">
392+ <a href="#" class="text-xl font-bold text-gray-800">Logo</a>
393+ </div>
394+ <div class="hidden md:flex space-x-8">
395+ <a href="#" class="text-gray-700 hover:text-blue-600 transition">Home</a>
396+ <a href="#" class="text-gray-700 hover:text-blue-600 transition">About</a>
397+ <a href="#" class="text-gray-700 hover:text-blue-600 transition">Services</a>
398+ <a href="#" class="text-gray-700 hover:text-blue-600 transition">Contact</a>
399+ </div>
400+ <button class="md:hidden">
401+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
402+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
403+ </svg>
404+ </button>
405+ </div>
406+ </div>
407+</nav>
408+```
409+
410+### Form Elements
411+
412+```html
413+<form class="space-y-6 max-w-md mx-auto">
414+ <div>
415+ <label class="block text-sm font-medium text-gray-700 mb-2">
416+ Email
417+ </label>
418+ <input
419+ type="email"
420+ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
421+ placeholder="[email protected]"
422+ />
423+ </div>
424+
425+ <div>
426+ <label class="block text-sm font-medium text-gray-700 mb-2">
427+ Password
428+ </label>
429+ <input
430+ type="password"
431+ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
432+ />
433+ </div>
434+
435+ <div class="flex items-center">
436+ <input type="checkbox" class="mr-2" />
437+ <label class="text-sm text-gray-600">Remember me</label>
438+ </div>
439+
440+ <button
441+ type="submit"
442+ class="w-full bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-700 transition"
443+ >
444+ Sign In
445+ </button>
446+</form>
447+```
448+
449+### Modal/Dialog
450+
451+```html
452+<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
453+ <div class="bg-white rounded-lg shadow-xl max-w-md w-full p-6">
454+ <div class="flex justify-between items-center mb-4">
455+ <h3 class="text-xl font-bold">Modal Title</h3>
456+ <button class="text-gray-500 hover:text-gray-700">
457+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
458+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
459+ </svg>
460+ </button>
461+ </div>
462+ <p class="text-gray-700 mb-6">
463+ Modal content goes here.
464+ </p>
465+ <div class="flex justify-end space-x-4">
466+ <button class="px-4 py-2 text-gray-600 hover:text-gray-800">
467+ Cancel
468+ </button>
469+ <button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
470+ Confirm
471+ </button>
472+ </div>
473+ </div>
474+</div>
475+```
476+
477+## Responsive Design Patterns
478+
479+### Mobile-First Responsive Layout
480+
481+```html
482+<div class="container mx-auto px-4">
483+ <!-- Hero Section -->
484+ <div class="flex flex-col md:flex-row items-center gap-8 py-12">
485+ <div class="flex-1">
486+ <h1 class="text-3xl md:text-5xl font-bold mb-4">
487+ Welcome to Our Site
488+ </h1>
489+ <p class="text-lg text-gray-600 mb-6">
490+ Build amazing things with Tailwind CSS
491+ </p>
492+ <button class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">
493+ Get Started
494+ </button>
495+ </div>
496+ <div class="flex-1">
497+ <img src="hero.jpg" class="w-full rounded-lg shadow-lg" />
498+ </div>
499+ </div>
500+</div>
501+```
502+
503+### Responsive Grid Gallery
504+
505+```html
506+<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 p-4">
507+ <div class="aspect-square bg-gray-200 rounded-lg overflow-hidden">
508+ <img src="image1.jpg" class="w-full h-full object-cover hover:scale-105 transition" />
509+ </div>
510+ <div class="aspect-square bg-gray-200 rounded-lg overflow-hidden">
511+ <img src="image2.jpg" class="w-full h-full object-cover hover:scale-105 transition" />
512+ </div>
513+ <!-- More items... -->
514+</div>
515+```
516+
517+## Dark Mode
518+
519+### Basic Dark Mode Support
520+
521+```html
522+<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
523+ <h1 class="text-gray-900 dark:text-white">Title</h1>
524+ <p class="text-gray-600 dark:text-gray-400">Description</p>
525+</div>
526+```
527+
528+Enable dark mode in tailwind.config.js:
529+
530+```javascript
531+module.exports = {
532+ darkMode: 'class', // or 'media'
533+ // ...
534+}
535+```
536+
537+## Animations & Transitions
538+
539+### Basic Transitions
540+
541+```html
542+<button class="bg-blue-500 hover:bg-blue-700 transition duration-300">
543+ Smooth transition
544+</button>
545+```
546+
547+### Transform Effects
548+
549+```html
550+<div class="transform hover:scale-110 transition duration-300">
551+ Scale on hover
552+</div>
553+
554+<img class="transform hover:rotate-6 transition duration-300" />
555+```
556+
557+### Built-in Animations
558+
559+```html
560+<div class="animate-spin">Spinning</div>
561+<div class="animate-pulse">Pulsing</div>
562+<div class="animate-bounce">Bouncing</div>
563+```
564+
565+## Performance Optimization
566+
567+### Bundle Size Optimization
568+
569+Configure content sources for optimal purging:
570+
571+```javascript
572+// tailwind.config.js
573+export default {
574+ content: [
575+ "./index.html",
576+ "./src/**/*.{js,ts,jsx,tsx,vue,svelte}",
577+ "./node_modules/@mycompany/ui-lib/**/*.{js,ts,jsx,tsx}",
578+ ],
579+ // Enable JIT for faster builds
580+ jit: true,
581+}
582+```
583+
584+### CSS Optimization Techniques
585+
586+```html
587+<!-- Use content-visibility for offscreen content -->
588+<div class="content-visibility-auto">
589+ <div>Heavy content that's initially offscreen</div>
590+</div>
591+
592+<!-- Optimize images with aspect-ratio -->
593+<img class="aspect-video w-full object-cover" src="video.jpg" alt="Video thumbnail" />
594+
595+<!-- Use contain for paint optimization -->
596+<div class="contain-layout">
597+ Complex layout that doesn't affect outside elements
598+</div>
599+```
600+
601+### Development Performance
602+
603+```css
604+/* Enable CSS-first configuration in v4.1 */
605+@import "tailwindcss";
606+
607+@theme {
608+ /* Define once, use everywhere */
609+ --color-brand: #3b82f6;
610+ --font-mono: "Fira Code", monospace;
611+}
612+
613+/* Critical CSS for above-the-fold content */
614+@layer critical {
615+ .hero-title {
616+ @apply text-4xl md:text-6xl font-bold;
617+ }
618+}
619+```
620+
621+## Accessibility Guidelines
622+
623+### Focus Management
624+
625+```html
626+<!-- Custom focus styles that meet WCAG AA -->
627+<button class="focus:outline-none focus:ring-4 focus:ring-blue-500 focus:ring-offset-2">
628+ Accessible Button
629+</button>
630+
631+<!-- Skip links for keyboard navigation -->
632+<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4">
633+ Skip to main content
634+</a>
635+```
636+
637+### Screen Reader Support
638+
639+```html
640+<!-- Semantic buttons with ARIA labels -->
641+<button aria-label="Close dialog" class="p-2">
642+ <svg class="w-5 h-5" fill="none" stroke="currentColor">
643+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
644+ </svg>
645+</button>
646+
647+<!-- Descriptive links -->
648+<a href="/docs" aria-describedby="docs-description">
649+ Documentation
650+</a>
651+<p id="docs-description" class="sr-only">
652+ Learn how to use our API and integration guides
653+</p>
654+```
655+
656+### Color Contrast
657+
658+```html
659+<!-- Ensure sufficient contrast ratios -->
660+<div class="bg-gray-900 text-white">
661+ High contrast text (WCAG AAA)
662+</div>
663+
664+<div class="bg-blue-500 text-blue-100">
665+ Good contrast on colored backgrounds
666+</div>
667+
668+<!-- Use contrast utilities for testing -->
669+<div class="bg-red-500 text-white contrast-more:bg-red-600 contrast-more:text-red-100">
670+ Adjusts for high contrast mode
671+</div>
672+```
673+
674+### Motion Preferences
675+
676+```html
677+<!-- Respect prefers-reduced-motion -->
678+<div class="transform transition-transform motion-reduce:transition-none">
679+ Doesn't animate when user prefers reduced motion
680+</div>
681+
682+<!-- Conditional animations -->
683+<div class="animate-pulse motion-safe:hover:animate-spin">
684+ Only animates when motion is preferred
685+</div>
686+```
687+
688+## Best Practices
689+
690+1. **Mobile-First**: Start with mobile styles, add responsive prefixes for larger screens
691+2. **Consistent Spacing**: Use Tailwind's spacing scale (4, 8, 12, 16, etc.)
692+3. **Color Palette**: Stick to Tailwind's color system for consistency
693+4. **Component Extraction**: Extract repeated patterns into components
694+5. **Utility Composition**: Prefer utility classes over @apply for better maintainability
695+6. **Semantic HTML**: Use proper HTML elements with Tailwind classes
696+7. **Performance**: Configure content paths correctly for optimal CSS purging
697+8. **Accessibility**: Include focus styles, ARIA labels, and respect user preferences
698+9. **CSS-First Config**: Use @theme directive for v4.1+ instead of JavaScript config
699+10. **Custom Utilities**: Create reusable utilities with @utility for complex patterns
700+
701+## Configuration
702+
703+### CSS-First Configuration (v4.1+)
704+
705+Use the `@theme` directive for CSS-based configuration:
706+
707+```css
708+/* src/styles.css */
709+@import "tailwindcss";
710+
711+@theme {
712+ /* Custom colors */
713+ --color-brand-50: #f0f9ff;
714+ --color-brand-500: #3b82f6;
715+ --color-brand-900: #1e3a8a;
716+
717+ /* Custom fonts */
718+ --font-display: "Inter", system-ui, sans-serif;
719+ --font-mono: "Fira Code", monospace;
720+
721+ /* Custom spacing */
722+ --spacing-128: 32rem;
723+
724+ /* Custom animations */
725+ --animate-fade-in: fadeIn 0.5s ease-in-out;
726+
727+ /* Custom breakpoints */
728+ --breakpoint-3xl: 1920px;
729+}
730+
731+/* Define custom animations */
732+@keyframes fadeIn {
733+ from { opacity: 0; }
734+ to { opacity: 1; }
735+}
736+
737+/* Custom utilities */
738+@utility content-auto {
739+ content-visibility: auto;
740+}
741+```
742+
743+### JavaScript Configuration (Legacy)
744+
745+```javascript
746+/** @type {import('tailwindcss').Config} */
747+export default {
748+ content: [
749+ "./index.html",
750+ "./src/**/*.{js,ts,jsx,tsx,vue,svelte}",
751+ ],
752+ theme: {
753+ extend: {
754+ colors: {
755+ primary: {
756+ 50: '#f0f9ff',
757+ 500: '#3b82f6',
758+ 900: '#1e3a8a',
759+ },
760+ },
761+ fontFamily: {
762+ sans: ['Inter', 'system-ui', 'sans-serif'],
763+ },
764+ spacing: {
765+ '128': '32rem',
766+ },
767+ },
768+ },
769+ plugins: [],
770+}
771+```
772+
773+### Vite Integration (v4.1+)
774+
775+```javascript
776+// vite.config.ts
777+import { defineConfig } from 'vite'
778+import tailwindcss from '@tailwindcss/vite'
779+
780+export default defineConfig({
781+ plugins: [
782+ tailwindcss(),
783+ ],
784+})
785+```
786+
787+## Advanced v4.1 Features
788+
789+### Native CSS Custom Properties
790+
791+```html
792+<div class="bg-[var(--color-brand-500)] text-[var(--color-white)]">
793+ Using CSS custom properties directly
794+</div>
795+```
796+
797+### Enhanced Arbitrary Values
798+
799+```html
800+<!-- Complex grid with custom tracks -->
801+<div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
802+ Responsive grid without custom CSS
803+</div>
804+
805+<!-- Custom animation timing -->
806+<div class="animate-bounce ease-[cubic-bezier(0.68,-0.55,0.265,1.55)]">
807+ Bounce with custom easing
808+</div>
809+```
810+
811+### Container Queries
812+
813+```html
814+<!-- Component that responds to its container size -->
815+<div class="@container">
816+ <div class="@lg:text-xl @2xl:text-2xl">
817+ Text size based on container, not viewport
818+ </div>
819+</div>
820+```
821+
822+## Common Patterns with React/JSX
823+
824+```tsx
825+import { useState } from 'react';
826+
827+function Button({
828+ variant = 'primary',
829+ size = 'md',
830+ children
831+}: {
832+ variant?: 'primary' | 'secondary';
833+ size?: 'sm' | 'md' | 'lg';
834+ children: React.ReactNode;
835+}) {
836+ const baseClasses = 'font-semibold rounded transition';
837+
838+ const variantClasses = {
839+ primary: 'bg-blue-600 text-white hover:bg-blue-700',
840+ secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
841+ };
842+
843+ const sizeClasses = {
844+ sm: 'px-3 py-1 text-sm',
845+ md: 'px-4 py-2 text-base',
846+ lg: 'px-6 py-3 text-lg',
847+ };
848+
849+ return (
850+ <button
851+ className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`}
852+ >
853+ {children}
854+ </button>
855+ );
856+}
857+```
858+
859+## References
860+
861+- Tailwind CSS Docs: https://tailwindcss.com/docs
862+- Tailwind UI: https://tailwindui.com
863+- Tailwind Play: https://play.tailwindcss.com
864+- Headless UI: https://headlessui.com
1@@ -0,0 +1,508 @@
2+# Tailwind CSS Documentation
3+
4+Tailwind CSS is a utility-first CSS framework that generates styles by scanning HTML, JavaScript, and template files for class names. It provides a comprehensive design system through CSS utility classes, enabling rapid UI development without writing custom CSS. The framework operates at build-time, analyzing source files and generating only the CSS classes actually used in the project, resulting in optimized production bundles with zero runtime overhead.
5+
6+The framework includes an extensive default color palette (18 colors with 11 shades each), responsive breakpoint system, customizable design tokens via CSS custom properties, and support for dark mode, pseudo-classes, pseudo-elements, and media queries through variant prefixes. Tailwind CSS v4.1 introduces CSS-first configuration using the `@theme` directive, native support for custom utilities via `@utility`, seamless integration with modern build tools through Vite, PostCSS, and framework-specific plugins, and enhanced arbitrary value syntax for maximum flexibility.
7+
8+## Installation with Vite
9+
10+Installing Tailwind CSS using the Vite plugin for modern JavaScript frameworks.
11+
12+```bash
13+# Create a new Vite project
14+npm create vite@latest my-project
15+cd my-project
16+
17+# Install Tailwind CSS and Vite plugin
18+npm install tailwindcss @tailwindcss/vite
19+```
20+
21+```javascript
22+// vite.config.ts
23+import { defineConfig } from 'vite'
24+import tailwindcss from '@tailwindcss/vite'
25+
26+export default defineConfig({
27+ plugins: [
28+ tailwindcss(),
29+ ],
30+})
31+```
32+
33+```css
34+/* src/style.css */
35+@import "tailwindcss";
36+```
37+
38+```html
39+
40+
41+
42+# Hello world!
43+
44+```
45+
46+## Utility Classes with Variants
47+
48+Applying conditional styles using variant prefixes for hover, focus, and responsive breakpoints.
49+
50+```html
51+
52+ Save changes
53+
54+Content adapts to color scheme preference
55+
56+ Submit
57+
58+```
59+
60+## Custom Theme Configuration
61+
62+Defining custom design tokens using the `@theme` directive in CSS.
63+
64+```css
65+/* app.css */
66+@import "tailwindcss";
67+
68+@theme {
69+ /* Custom fonts */
70+ --font-display: "Satoshi", "sans-serif";
71+ --font-body: "Inter", system-ui, sans-serif;
72+
73+ /* Custom colors */
74+ --color-brand-50: oklch(0.98 0.02 264);
75+ --color-brand-100: oklch(0.95 0.05 264);
76+ --color-brand-500: oklch(0.55 0.22 264);
77+ --color-brand-900: oklch(0.25 0.12 264);
78+
79+ /* Custom breakpoints */
80+ --breakpoint-3xl: 120rem;
81+ --breakpoint-4xl: 160rem;
82+
83+ /* Custom spacing */
84+ --spacing-18: calc(var(--spacing) * 18);
85+
86+ /* Custom animations */
87+ --ease-fluid: cubic-bezier(0.3, 0, 0, 1);
88+ --ease-snappy: cubic-bezier(0.2, 0, 0, 1);
89+}
90+```
91+
92+```html
93+
94+Custom design system
95+
96+```
97+
98+## Arbitrary Values
99+
100+Using square bracket notation for one-off custom values without leaving HTML.
101+
102+```html
103+
104+Pixel-perfect positioning
105+
106+Custom hex colors, font sizes, and content
107+
108+Any CSS property
109+
110+Reference custom properties
111+
112+Complex grid layouts
113+
114+Font size from CSS variable
115+
116+Color from CSS variable
117+
118+```
119+
120+## Color System
121+
122+Working with Tailwind's comprehensive color palette and opacity modifiers.
123+
124+```html
125+
126+Color utilities across all properties
127+
128+Alpha channel with percentage
129+
130+Arbitrary opacity values
131+
132+Opacity from CSS variable
133+
134+Adapts to color scheme
135+
136+
137+```
138+
139+## Dark Mode
140+
141+Implementing dark mode with CSS media queries or manual toggle.
142+
143+```html
144+
145+Content automatically adapts
146+
147+
148+```
149+
150+```css
151+/* Manual dark mode toggle with class selector */
152+@import "tailwindcss";
153+
154+@custom-variant dark (&:where(.dark, .dark *));
155+```
156+
157+```html
158+
159+Controlled by .dark class
160+
161+
162+
163+
164+```
165+
166+```javascript
167+// Dark mode toggle logic
168+// On page load or theme change
169+document.documentElement.classList.toggle(
170+ "dark",
171+ localStorage.theme === "dark" ||
172+ (!("theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)
173+);
174+
175+// User chooses light mode
176+localStorage.theme = "light";
177+
178+// User chooses dark mode
179+localStorage.theme = "dark";
180+
181+// User chooses system preference
182+localStorage.removeItem("theme");
183+```
184+
185+## State Variants
186+
187+Styling elements based on pseudo-classes and parent/sibling state.
188+
189+```html
190+
191+- Item content
192+
193+
194+**Title**
195+Description
196+
197+Please provide a valid email address.
198+
199+
200+ Option
201+
202+```
203+
204+## Responsive Design
205+
206+Building mobile-first responsive layouts with breakpoint variants.
207+
208+```html
209+
210+# Responsive heading
211+
212+Text scales with viewport
213+
214+
215+Desktop only
216+
217+Mobile only
218+
219+Custom breakpoint
220+
221+Below medium
222+
223+```
224+
225+## Custom Utilities
226+
227+Creating reusable custom utility classes with variant support.
228+
229+```css
230+/* Simple custom utility */
231+@utility content-auto {
232+ content-visibility: auto;
233+}
234+
235+/* Complex utility with nesting */
236+@utility scrollbar-hidden {
237+ &::-webkit-scrollbar {
238+ display: none;
239+ }
240+}
241+
242+/* Functional utility with theme values */
243+@theme {
244+ --tab-size-2: 2;
245+ --tab-size-4: 4;
246+ --tab-size-github: 8;
247+}
248+
249+@utility tab-* {
250+ tab-size: --value(--tab-size-*);
251+}
252+
253+/* Supporting arbitrary, bare, and theme values */
254+@utility opacity-* {
255+ opacity: --value([percentage]);
256+ opacity: calc(--value(integer) * 1%);
257+ opacity: --value(--opacity-*);
258+}
259+
260+/* Utility with modifiers */
261+@utility text-* {
262+ font-size: --value(--text-*, [length]);
263+ line-height: --modifier(--leading-*, [length], [*]);
264+}
265+
266+/* Negative value support */
267+@utility inset-* {
268+ inset: --spacing(--value(integer));
269+ inset: --value([percentage], [length]);
270+}
271+
272+@utility -inset-* {
273+ inset: --spacing(--value(integer) * -1);
274+ inset: calc(--value([percentage], [length]) * -1);
275+}
276+```
277+
278+```html
279+
280+Custom utilities work with variants
281+
282+Variants and arbitrary values supported
283+
284+Utility with modifier (font-size/line-height)
285+
286+```
287+
288+## Custom Variants
289+
290+Registering custom conditional styles with the `@custom-variant` directive.
291+
292+```css
293+/* Simple custom variant */
294+@custom-variant theme-midnight (&:where([data-theme="midnight"] *));
295+
296+/* Variant with media query */
297+@custom-variant any-hover {
298+ @media (any-hover: hover) {
299+ &:hover {
300+ @slot;
301+ }
302+ }
303+}
304+
305+/* ARIA state variant */
306+@custom-variant aria-asc (&[aria-sort="ascending"]);
307+@custom-variant aria-desc (&[aria-sort="descending"]);
308+
309+/* Data attribute variant */
310+@custom-variant data-checked (&[data-ui~="checked"]);
311+```
312+
313+```html
314+
315+ Midnight theme button
316+
317+
318+ Sortable column
319+
320+Checked state
321+
322+One-off custom selectors
323+
324+```
325+
326+## Applying Variants in CSS
327+
328+Using the `@variant` directive to apply variants within custom CSS.
329+
330+```css
331+/* Single variant */
332+.my-element {
333+ background: white;
334+
335+ @variant dark {
336+ background: black;
337+ }
338+}
339+
340+/* Nested variants */
341+.my-button {
342+ background: white;
343+
344+ @variant dark {
345+ background: gray;
346+
347+ @variant hover {
348+ background: black;
349+ }
350+ }
351+}
352+
353+/* Compiled output */
354+.my-element {
355+ background: white;
356+}
357+
358+@media (prefers-color-scheme: dark) {
359+ .my-element {
360+ background: black;
361+ }
362+}
363+```
364+
365+## Layer Organization
366+
367+Organizing custom styles into Tailwind's cascade layers.
368+
369+```css
370+@import "tailwindcss";
371+
372+/* Base styles for HTML elements */
373+@layer base {
374+ h1 {
375+ font-size: var(--text-2xl);
376+ font-weight: bold;
377+ }
378+
379+ h2 {
380+ font-size: var(--text-xl);
381+ font-weight: 600;
382+ }
383+
384+ body {
385+ font-family: var(--font-body);
386+ }
387+}
388+
389+/* Reusable component classes */
390+@layer components {
391+ .btn {
392+ padding: --spacing(2) --spacing(4);
393+ border-radius: var(--radius);
394+ font-weight: 600;
395+ transition: all 150ms;
396+ }
397+
398+ .btn-primary {
399+ background-color: var(--color-blue-500);
400+ color: white;
401+ }
402+
403+ .card {
404+ background-color: var(--color-white);
405+ border-radius: var(--radius-lg);
406+ padding: --spacing(6);
407+ box-shadow: var(--shadow-xl);
408+ }
409+
410+ /* Third-party component overrides */
411+ .select2-dropdown {
412+ border-radius: var(--radius);
413+ box-shadow: var(--shadow-lg);
414+ }
415+}
416+```
417+
418+```html
419+
420+Square corners despite card class
421+
422+ Component with utility overrides
423+
424+```
425+
426+## Functions and Directives
427+
428+Using Tailwind's CSS functions for dynamic values and opacity adjustments.
429+
430+```css
431+/* Alpha function for opacity */
432+.my-element {
433+ color: --alpha(var(--color-lime-300) / 50%);
434+ background: --alpha(var(--color-blue-500) / 25%);
435+}
436+
437+/* Spacing function */
438+.my-element {
439+ margin: --spacing(4);
440+ padding: calc(--spacing(6) - 1px);
441+}
442+
443+/* In arbitrary values */
444+
445+/* Source directive for additional content */
446+@source "../node_modules/@my-company/ui-lib";
447+
448+/* Apply directive for inline utilities */
449+.select2-dropdown {
450+ @apply rounded-b-lg shadow-md;
451+}
452+
453+.select2-search {
454+ @apply rounded border border-gray-300;
455+}
456+
457+.select2-results__group {
458+ @apply text-lg font-bold text-gray-900;
459+}
460+```
461+
462+## Pseudo-elements
463+
464+Styling ::before, ::after, ::placeholder, and other pseudo-elements.
465+
466+```html
467+
468+ Email
469+
470+
471+- First item
472+- Second item
473+
474+Select this text to see custom colors
475+
476+Typography with pseudo-elements
477+
478+```
479+
480+## Media Queries
481+
482+Conditional styling based on user preferences and device capabilities.
483+
484+```html
485+
486+ Respects user preference
487+
488+ Only animates if motion allowed
489+
490+ Adjusts for contrast needs
491+
492+
493+Hidden in portrait mode
494+
495+Layout adapts to orientation
496+
497+ Not shown when printing
498+
499+Only visible in print
500+
501+Progressive enhancement
502+
503+```
504+
505+## Summary
506+
507+Tailwind CSS provides a complete utility-first design system that eliminates the need for writing custom CSS in most cases. The framework's primary use cases include rapid prototyping, building production applications with consistent design systems, creating responsive layouts, implementing dark mode, and maintaining design consistency across large teams. By using utility classes directly in markup, developers can iterate quickly, avoid naming conventions, and prevent CSS bloat since only used styles are generated.
508+
509+The v4.1 release enhances the developer experience with CSS-first configuration, eliminating JavaScript configuration files for most projects. Integration patterns include using the Vite plugin for modern frameworks, PostCSS for custom build pipelines, the Tailwind CLI for simple projects, and CDN scripts for rapid prototyping. The framework excels at component-driven development when combined with React, Vue, Svelte, or other modern frameworks, where utility classes are co-located with component logic. Custom design systems can be fully defined in CSS using `@theme`, with project-specific utilities and variants extending the framework's capabilities without writing JavaScript plugins.
+39,
-0
1@@ -0,0 +1,39 @@
2+---
3+name: web-design-guidelines
4+description: Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
5+metadata:
6+ author: vercel
7+ version: "1.0.0"
8+ argument-hint: <file-or-pattern>
9+---
10+
11+# Web Interface Guidelines
12+
13+Review files for compliance with Web Interface Guidelines.
14+
15+## How It Works
16+
17+1. Fetch the latest guidelines from the source URL below
18+2. Read the specified files (or prompt user for files/pattern)
19+3. Check against all rules in the fetched guidelines
20+4. Output findings in the terse `file:line` format
21+
22+## Guidelines Source
23+
24+Fetch fresh guidelines before each review:
25+
26+```
27+https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md
28+```
29+
30+Use WebFetch to retrieve the latest rules. The fetched content contains all the rules and output format instructions.
31+
32+## Usage
33+
34+When a user provides a file or pattern argument:
35+1. Fetch guidelines from the source URL above
36+2. Read the specified files
37+3. Apply all rules from the fetched guidelines
38+4. Output findings using the format specified in the guidelines
39+
40+If no files specified, ask the user which files to review.
+164,
-0
1@@ -0,0 +1,164 @@
2+---
3+name: working-with-jj
4+description: Expert guidance for using JJ (Jujutsu) version control system. Use when working with JJ, whatever the subject. Operations, revsets, templates, debugging change evolution, etc. Covers JJ commands, template system, evolog, operations log, and interoperability with git remotes.
5+version_target: "0.36.x"
6+---
7+
8+# JJ (Jujutsu) Version Control Helper
9+
10+## Core Principles
11+
12+- **Change IDs** (immutable) vs **Commit IDs** (content-based hashes that change
13+ on edit)
14+- **Operations log** - every operation can be undone (progressive: multiple `jj undo` goes further back, `jj redo` reverses)
15+- **No staging area** - working copy auto-snapshots
16+- **Conflicts don't block** - resolve later
17+- **Commits are lightweight** - edit freely
18+- **Colocated by default** - Repos have both `.jj` and `.git` (since v0.34)
19+- **Three DSLs**:
20+ - _revsets_: select across revisions - a revision (change) ID is a trivial but fully valid singleton revset
21+ - _filesets_: select across files in the repository - a regular filepath is a trivial but fully valid singleton fileset
22+ - _templates_: select which info to log and how to show it
23+ - Many jj commands expect expressions using either of these DSLs, to select what to show/operate on
24+
25+## Essential Commands
26+
27+```bash
28+jj log -r <revset> [-p] # View history (--patch/-p: include diffs, --count: just count)
29+jj log -r <revset> -G # -G is short for --no-graph
30+jj show -r <rev> # Show revision details (description + diff)
31+jj evolog -r <rev> [-p] # View a revision's evolution
32+jj new [-A] <base> # Create revision and edit it (-A: insert between <base> and its children rather than just on top of base)
33+jj new --no-edit <base> # Create without switching
34+jj edit <rev> # Switch to editing revision
35+jj desc -r <rev> -m "text" # Set description
36+jj metaedit -r <rev> -m "text" # Modify metadata (author, timestamps, description)
37+
38+jj diff # Changes in @
39+jj diff -r <revset> # Changes in revset (need to be contiguous)
40+jj diff -f <rev1> -t <rev2> # Differences between two states
41+jj file show -r <rev> <fileset> # Show file contents at revision (without switching)
42+jj file show -r <rev> **/*.md -T '"=== " ++ path ++ " ===\n"' # Multiple files with path headers
43+jj restore <fileset> # Discard changes to files
44+jj restore --from <commit-id> <fileset> # Restore from another revision/commit
45+
46+jj split -r <rev> <paths> -m "text" # Split into two revisions
47+jj absorb # Auto-squash changes into ancestor commits
48+
49+jj rebase -s <src> -o <dest> # Rebase with descendants onto <dest>
50+jj rebase -r <rev> -o <dest> # Rebase single revision onto <dest>
51+# NOTE: -d/--destination is deprecated, use -o/--onto instead
52+
53+jj file annotate <path> # Blame: who changed each line
54+jj bisect run -- <cmd> # Binary search for bug-introducing commit
55+```
56+
57+## Additional Commands
58+
59+```bash
60+jj undo # Undo last operation (progressive - repeat to go further back)
61+jj redo # Redo undone operation
62+jj sign -r <rev> # Cryptographically sign commit
63+jj unsign -r <rev> # Remove signature
64+jj revert -r <rev> # Create commit that reverts changes (replaces old jj backout)
65+jj tag set <name> -r <rev> # Create/update local tag
66+jj tag delete <name> # Delete local tag
67+jj git colocation enable # Convert to colocated repo
68+jj git colocation disable # Convert to non-colocated
69+```
70+
71+## Quick Revset Reference
72+
73+```bash
74+@, @-, @-- # Working copy, parent(s), grandparent(s)
75+::@ # Ancestors
76+@:: # Descendants
77+mine() # Your changes
78+conflicted() # Has conflicts (renamed from conflict() in v0.33)
79+visible() # Visible revisions (built-in alias)
80+hidden() # Hidden revisions (built-in alias)
81+description(substring-i:"text") # Match description (partial, case-insensitive)
82+subject(substring:"text") # Match first line only
83+signed() # Cryptographically signed commits
84+A | B, A & B, A ~ B # Union, intersection, difference
85+change_id(prefix) # Explicit change ID prefix lookup
86+parents(x, 2) # Parents with depth
87+exactly(x, 3) # Assert exactly N revisions
88+```
89+
90+See `references/revsets.md` for comprehensive revset patterns.
91+
92+## Common Pitfalls
93+
94+### 1. Use `-r` not `--revisions`
95+
96+```bash
97+jj log -r xyz # ✅
98+jj log --revisions xyz # ❌
99+```
100+
101+### 2. Use `--no-edit` for parallel branches
102+
103+```bash
104+jj new parent -m "A"; jj new -m "B" # ❌ B is child of A!
105+jj new --no-edit parent -m "A"; jj new --no-edit parent -m "B" # ✅ Both children of parent
106+```
107+
108+### 3. Quote revsets in shell
109+
110+```bash
111+jj log -r 'description(substring:"[todo]")' # ✅
112+```
113+
114+### 4. Use `-o`/`--onto` instead of `-d`/`--destination` (v0.36+)
115+
116+```bash
117+jj rebase -s xyz -o main # ✅ New syntax
118+jj rebase -s xyz -d main # ⚠️ Deprecated (still works but warns)
119+```
120+
121+### 5. Symbol expressions are stricter (v0.32+)
122+
123+Revset symbols no longer resolve to multiple revisions:
124+
125+```bash
126+jj log -r abc # ❌ Error if 'abc' matches multiple change IDs
127+jj log -r 'change_id(abc)' # ✅ Explicitly query by prefix
128+jj log -r 'bookmarks(abc)' # ✅ For bookmark name patterns
129+```
130+
131+### 6. Glob patterns are default in filesets (v0.36+)
132+
133+```bash
134+jj diff 'src/*.rs' # Matches glob pattern by default
135+jj diff 'cwd:"src/*.rs"' # Use cwd: prefix for literal path with special chars
136+```
137+
138+## Scripts
139+
140+Helper scripts in `scripts/`. Add to PATH or invoke directly.
141+
142+| Script | Purpose |
143+| ----------------------------------------- | -------------------------------------- |
144+| `jj-show-desc [REV]` | Print full description only |
145+| `jj-desc-transform <REV> <CMD...>` | Pipe description through command |
146+| `jj-batch-desc <SED_FILE> <REV...>` | Batch transform descriptions |
147+| `jj-checkpoint [NAME]` | Record op ID before risky operations |
148+
149+## Recovery
150+
151+```bash
152+jj op log # Find operation before problem
153+jj op restore <op-id> # Restore the WHOLE repository (history included) to that state
154+```
155+
156+## References
157+
158+- The `jj` exe is self-documenting:
159+ - Run `jj help -k bookmarks` - JJ bookmarks, how they relate to Git branches and how to push/fetch them from Git remotes
160+ - Run `jj help -k revsets` - Revset DSL syntax and patterns
161+ - Run `jj help -k filesets` - Filepath selection DSL, ie. how to tell jj commands to operate only on specific files
162+ - Run `jj help -k templates` - Template language and custom output
163+ - All jj subcommands have a pretty detailed `--help` page
164+- `references/command-syntax.md` - Command flag details
165+- `references/batch-operations.md` - Complex batch transformations on revision descriptions
1@@ -0,0 +1,165 @@
2+# Batch Operations on Multiple Revisions
3+
4+## Problem
5+
6+When you need to update descriptions for multiple revisions (e.g., replacing line number references with labels), bash syntax and piping can be tricky.
7+
8+## Anti-Pattern
9+
10+```bash
11+# ❌ This will fail with syntax errors
12+for rev in unxn mktt stnq; do
13+ jj log -r $rev | sed 's/L123/label/' | jj desc -r $rev --stdin
14+done
15+
16+# Issues:
17+# 1. Missing -n1 --no-graph -T description (gets full log output)
18+# 2. Unquoted variables ($rev) can break with special chars
19+# 3. Complex pipes in one-liners are fragile
20+```
21+
22+## Pattern 1: Intermediate Files (Recommended)
23+
24+```bash
25+# ✅ Robust pattern using temporary files
26+for rev in unxn mktt stnq rwyq roww; do
27+ # Extract description to file
28+ jj log -r "$rev" -n1 --no-graph -T description > /tmp/desc_${rev}_old.txt
29+
30+ # Transform using sed/awk/etc
31+ sed -f /tmp/replacements.sed /tmp/desc_${rev}_old.txt > /tmp/desc_${rev}_new.txt
32+
33+ # Apply back to revision
34+ jj desc -r "$rev" --stdin < /tmp/desc_${rev}_new.txt
35+done
36+
37+echo "✅ All descriptions updated"
38+```
39+
40+**Benefits:**
41+- Each step is visible and debuggable
42+- Can inspect intermediate files if something goes wrong
43+- Easy to retry individual revisions
44+- Works with complex transformations
45+
46+## Pattern 2: One Command at a Time
47+
48+```bash
49+# ✅ Alternative: Sequential approach
50+jj log -r unxn -n1 --no-graph -T description | \
51+ sed 's/L123/@label/' > /tmp/desc_unxn.txt
52+jj desc -r unxn --stdin < /tmp/desc_unxn.txt
53+
54+jj log -r mktt -n1 --no-graph -T description | \
55+ sed 's/L123/@label/' > /tmp/desc_mktt.txt
56+jj desc -r mktt --stdin < /tmp/desc_mktt.txt
57+
58+# etc.
59+```
60+
61+**Benefits:**
62+- Even more explicit
63+- Easy to stop/resume
64+- Perfect for copy-paste execution
65+
66+## Pattern 3: Using sed Script File
67+
68+```bash
69+# Create reusable sed script
70+cat > /tmp/replacements.sed << 'EOF'
71+s/L596-617/@types-de-cartes/g
72+s/L1242-1253/@carte-eglise/g
73+s/L659-665/@couts-marche/g
74+EOF
75+
76+# Apply to all revisions
77+for rev in unxn mktt stnq; do
78+ jj log -r "$rev" -n1 --no-graph -T description | \
79+ sed -f /tmp/replacements.sed | \
80+ jj desc -r "$rev" --stdin
81+done
82+```
83+
84+**Benefits:**
85+- Reusable transformation logic
86+- Easy to test sed script independently
87+- Cleaner loop body
88+
89+## Common Mistakes
90+
91+### 1. Missing Template Specification
92+
93+```bash
94+# ❌ Wrong: gets formatted log output
95+jj log -r xyz | sed 's/old/new/'
96+
97+# ✅ Correct: extract just description
98+jj log -r xyz -n1 --no-graph -T description | sed 's/old/new/'
99+```
100+
101+### 2. Unquoted Variables
102+
103+```bash
104+# ❌ Breaks with special characters in rev names
105+for rev in a b c; do
106+ jj log -r $rev # Unquoted
107+done
108+
109+# ✅ Always quote
110+for rev in a b c; do
111+ jj log -r "$rev" # Quoted
112+done
113+```
114+
115+### 3. Fragile One-Liners
116+
117+```bash
118+# ❌ Hard to debug, fragile
119+for rev in a b c; do jj log -r $rev -n1 --no-graph -T description | sed 's/x/y/' | jj desc -r $rev --stdin; done
120+
121+# ✅ Readable, debuggable
122+for rev in a b c; do
123+ jj log -r "$rev" -n1 --no-graph -T description | \
124+ sed 's/x/y/' > /tmp/desc_${rev}.txt
125+ jj desc -r "$rev" --stdin < /tmp/desc_${rev}.txt
126+done
127+```
128+
129+## Real-World Example
130+
131+Replacing all line number references with Typst labels across 10 revisions:
132+
133+```bash
134+# 1. Create sed replacement script
135+cat > /tmp/sed_replacements.txt << 'EOF'
136+s/5F\.typ L596-617/5F.typ @types-de-cartes/g
137+s/5F\.typ L1242-1253/5F.typ @carte-eglise-en-pierre/g
138+s/5F\.typ L659-665/5F.typ @couts-marche/g
139+# ... etc
140+EOF
141+
142+# 2. Process each revision
143+for rev in unxn mktt stnq rwyq roww wltq syun zkru mszz ovrv; do
144+ jj log -r "$rev" -n1 --no-graph -T description | \
145+ sed -f /tmp/sed_replacements.txt > "/tmp/desc_${rev}_new.txt"
146+ jj desc -r "$rev" --stdin < "/tmp/desc_${rev}_new.txt"
147+done
148+
149+# 3. Verify one result
150+jj log -r mktt -n1 --no-graph -T description | head -5
151+```
152+
153+## Verification
154+
155+Always verify the results after batch operations:
156+
157+```bash
158+# Quick check: first line of each description
159+for rev in unxn mktt stnq; do
160+ echo "=== $rev ==="
161+ jj log -r "$rev" -n1 --no-graph -T description | head -3
162+done
163+
164+# Or use jj log with custom template
165+jj log -r 'unxn | mktt | stnq' -T 'change_id.shortest(4) ++ " " ++ description.first_line() ++ "\n"'
166+```
1@@ -0,0 +1,232 @@
2+# JJ Command Syntax Reference
3+
4+## The `-r` Flag Confusion
5+
6+JJ commands are **inconsistent** with flag naming, which can be confusing:
7+
8+### Commands Using `-r` (Most Common)
9+
10+```bash
11+jj log -r <revset> # ✅ Short form only
12+jj desc -r <revset> # ✅ Short form only
13+jj show -r <revset> # ✅ Short form only
14+jj rebase -r <revset> # ✅ Short form only
15+jj edit -r <revset> # ✅ Short form only (no --revision)
16+```
17+
18+**Rule:** For most commands, use `-r` and **never** `--revisions` or
19+`--revision`.
20+
21+### Why This Matters
22+
23+```bash
24+# ❌ Common mistake: trying long form
25+jj desc --revisions xyz
26+# Error: unexpected argument '--revisions' found
27+
28+jj log --revision xyz
29+# Error: unexpected argument '--revision' found
30+
31+# ✅ Always use short form
32+jj desc -r xyz
33+jj log -r xyz
34+```
35+
36+## Commonly Used Short Flags
37+
38+```bash
39+-G # Short for --no-graph (v0.35+)
40+-o # Short for --onto (replaces -d in v0.36+)
41+-f / -t # Short for --from / --to (various commands)
42+```
43+
44+## Deprecated Flags (v0.36+)
45+
46+```bash
47+# ❌ Old # ✅ New
48+jj rebase -d main → jj rebase -o main # --onto replaces --destination
49+jj split -d main → jj split -o main
50+jj revert -d main → jj revert -o main
51+jj describe --edit → jj describe --editor # --editor replaces --edit
52+```
53+
54+## Command Patterns
55+
56+### Reading Revision Info
57+
58+```bash
59+# Get description only (for processing)
60+jj log -r <rev> -n1 --no-graph -T description
61+
62+# Get detailed info (human-readable)
63+jj log -r <rev> -n1 --no-graph -T builtin_log_detailed
64+
65+# Get compact one-liner
66+jj log -r <rev> -T 'change_id.shortest(4) ++ " " ++ description.first_line()'
67+```
68+
69+**Key flags:**
70+
71+- `-n1`: Limit to 1 revision
72+- `--no-graph`: No ASCII art graph
73+- `-T <template>`: Output template
74+- `-r <revset>`: Which revision(s)
75+
76+### Modifying Revisions
77+
78+```bash
79+# Change description from string
80+jj desc -r <rev> -m "New description"
81+
82+# Change description from stdin (for scripts)
83+echo "New description" | jj desc -r <rev> --stdin
84+
85+# Change description from file
86+jj desc -r <rev> --stdin < /path/to/description.txt
87+
88+# Pipeline pattern
89+jj log -r <rev> -n1 --no-graph -T description | \
90+ sed 's/old/new/' | \
91+ jj desc -r <rev> --stdin
92+```
93+
94+**Key insight:** `--stdin` is essential for scripted modifications.
95+
96+### Creating Revisions
97+
98+```bash
99+# Create and edit immediately (moves @)
100+jj new <parent> -m "Description"
101+
102+# Create without editing (@ stays put) - IMPORTANT for parallel branches
103+jj new --no-edit <parent> -m "Description"
104+
105+# Create with multiple parents (merge)
106+jj new --no-edit <parent1> <parent2> -m "Merge point"
107+```
108+
109+**Critical distinction:**
110+
111+- Without `--no-edit`: Your working copy (@) moves to the new revision
112+- With `--no-edit`: New revision created, but @ stays where it was
113+
114+## Revset Syntax
115+
116+### Basic Revsets
117+
118+```bash
119+@ # Working copy
120+<change-id> # Specific revision (e.g., abc, unxn)
121+<commit-id> # By commit hash
122+```
123+
124+### Operators
125+
126+```bash
127+<rev>::<rev> # Range (from..to, inclusive)
128+<rev>.. # All descendants
129+..<rev> # All ancestors
130+
131+# Examples
132+zyxu::@ # All revisions from zyxu to current
133+roww:: # roww and all its descendants
134+::@ # All ancestors of @
135+```
136+
137+### Functions
138+
139+```bash
140+description(glob:"pattern") # Match description
141+description(exact:"text") # Exact match
142+mine() # Your commits
143+```
144+
145+### Combining
146+
147+```bash
148+# Union (OR)
149+rev1 | rev2
150+
151+# Intersection (AND)
152+rev1 & rev2
153+
154+# Example: Your changes in current branch
155+mine() & ::@
156+```
157+
158+## Shell Quoting
159+
160+Revsets often need quoting because they contain special characters:
161+
162+```bash
163+# ❌ Shell interprets glob
164+jj log -r description(glob:"[todo]*")
165+
166+# ✅ Single quotes (safest)
167+jj log -r 'description(glob:"[todo]*")'
168+
169+# ✅ Double quotes with escaping
170+jj log -r "description(glob:\"[todo]*\")"
171+```
172+
173+**Rule:** When in doubt, use single quotes around revsets.
174+
175+## Common Patterns
176+
177+### Update Multiple Revisions
178+
179+```bash
180+# Pattern: Extract → Transform → Apply
181+for rev in a b c; do
182+ jj log -r "$rev" -n1 --no-graph -T description > /tmp/desc.txt
183+ # ... transform /tmp/desc.txt ...
184+ jj desc -r "$rev" --stdin < /tmp/desc.txt
185+done
186+```
187+
188+### Find and Update
189+
190+```bash
191+# Find all [todo] revisions
192+jj log -r 'description(glob:"[todo]*")'
193+
194+# Update specific one
195+jj log -r xyz -n1 --no-graph -T description | \
196+ sed 's/\[todo\]/[wip]/' | \
197+ jj desc -r xyz --stdin
198+```
199+
200+### Create Parallel Branches
201+
202+```bash
203+# All branch from same parent
204+parent=xyz
205+jj new --no-edit "$parent" -m "[todo] Branch A"
206+jj new --no-edit "$parent" -m "[todo] Branch B"
207+jj new --no-edit "$parent" -m "[todo] Branch C"
208+```
209+
210+## Debugging
211+
212+```bash
213+# Did my command work?
214+jj log -r <rev> -T 'change_id ++ " " ++ description.first_line()'
215+
216+# View full description
217+jj log -r <rev> -n1 --no-graph -T description
218+
219+# Check revision graph
220+jj log -r '<parent>::' -T builtin_log_compact
221+```
222+
223+## Quick Reference Card
224+
225+| Task | Command |
226+| ---------------- | ----------------------------------------------- |
227+| View description | `jj log -r <rev> -n1 --no-graph -T description` |
228+| Set description | `jj desc -r <rev> -m "text"` |
229+| Set from stdin | `jj desc -r <rev> --stdin` |
230+| Create (edit) | `jj new <parent> -m "text"` |
231+| Create (no edit) | `jj new --no-edit <parent> -m "text"` |
232+| Range query | `jj log -r '<from>::<to>'` |
233+| Find pattern | `jj log -r 'description(glob:"pat*")'` |
1@@ -0,0 +1,29 @@
2+#!/usr/bin/env bash
3+# Apply transformation to multiple revisions
4+# Usage: jj-batch-desc <SED_SCRIPT_FILE> <REV1> [REV2...]
5+# Example: jj-batch-desc /tmp/replacements.sed abc xyz mno
6+
7+set -euo pipefail
8+
9+if [[ $# -lt 2 ]]; then
10+ echo "Usage: jj-batch-desc <SED_SCRIPT_FILE> <REV1> [REV2...]" >&2
11+ exit 1
12+fi
13+
14+sed_script="$1"
15+shift
16+
17+if [[ ! -f "$sed_script" ]]; then
18+ echo "Error: sed script not found: $sed_script" >&2
19+ exit 1
20+fi
21+
22+for rev in "$@"; do
23+ echo "Processing $rev..."
24+ tmpfile="/tmp/jj_desc_${rev}_$$.txt"
25+ jj log -r "$rev" -n1 --no-graph -T description > "$tmpfile"
26+ sed -f "$sed_script" "$tmpfile" | jj desc -r "$rev" --stdin
27+ rm -f "$tmpfile"
28+done
29+
30+echo "✅ Processed $# revision(s)"
1@@ -0,0 +1,18 @@
2+#!/usr/bin/env bash
3+# Create a named checkpoint before risky operations
4+# Usage: jj-checkpoint [NAME]
5+# Later restore with: jj op restore <op-id>
6+# NAME defaults to "checkpoint"
7+
8+set -euo pipefail
9+
10+name="${1:-checkpoint}"
11+
12+# Get current operation ID
13+op_id=$(jj op log -n1 --no-graph -T 'self.id().short(12)')
14+
15+echo "📍 Checkpoint '$name' at operation: $op_id"
16+echo " Restore with: jj op restore $op_id"
17+echo ""
18+echo " Current state:"
19+jj log -r @ -n1 -T 'change_id.shortest(8) ++ " " ++ description.first_line()'
1@@ -0,0 +1,17 @@
2+#!/usr/bin/env bash
3+# Transform revision description through a command
4+# Usage: jj-desc-transform <REV> <COMMAND...>
5+# Example: jj-desc-transform @ sed 's/foo/bar/'
6+# Example: jj-desc-transform mxyz awk '/^##/{print; next} {print " "$0}'
7+
8+set -euo pipefail
9+
10+if [[ $# -lt 2 ]]; then
11+ echo "Usage: jj-desc-transform <REV> <COMMAND...>" >&2
12+ exit 1
13+fi
14+
15+rev="$1"
16+shift
17+
18+jj log -r "$rev" -n1 --no-graph -T description | "$@" | jj desc -r "$rev" --stdin
1@@ -0,0 +1,9 @@
2+#!/usr/bin/env bash
3+# Get revision description only (for reading or piping)
4+# Usage: jj-show-desc [REV]
5+# REV defaults to @
6+
7+set -euo pipefail
8+
9+rev="${1:-@}"
10+jj log -r "$rev" -n1 --no-graph -T description