ReScript in 2025 — Fast, Sound, and Ready for React (Hybrid Guide)
Highlights
- Sound, nominal types → fearless refactors.
- ADTs + pattern matching → simpler state & business rules.
- Pipes + labeled args → readable data‑first code.
- First‑class React → JSX, components, async/await support.
- Native compiler → fast feedback at scale.
- Interop → NPM bindings + human‑readable JS output.
Why it matters (in one minute)
TypeScript improved JS by adding types; ReScript improves types and then targets JS. That shift unlocks soundness, ADTs, and a simpler mental model for data flow — the things that tame large frontends.
Core Language Cheat‑Sheet
Option, Result, Variant
type option<'a> = None | Some('a)
type Result<'a, 'e> =
| Ok('a)
| Error('e)
type Role = Admin | User | Guest
Pattern match
let greet = (r: Role) => switch r {
| Admin => "Welcome, admin"
| User => "Hi!"
| Guest => "Please sign in"
}
Records & Tuples (immutable)
type person = {name: string, age: int}
let p = {name: "Ada", age: 25}
let older = { ...p, age: p.age + 1 }
let point: (float, float) = (10.0, 20.0)
Labeled args & pipes
let sub = (~first: int, ~second: int) => first - second
let x = sub(~second=2, ~first=5)
let total =
[1,2,3]
->Belt.Array.map(x => x + 1)
->Belt.Array.reduce(0, (a, v) => a + v)
React with @rescript/react
module Button = {
@react.component
let make = (~label: string, ~onClick: unit => unit) => {
<button onClick> {React.string(label)} </button>
}
}
Interop with DOM & libs via externals:
@module("react-dom")
external render: (React.element, Dom.element) => unit = "render"
%raw(`import "styles.css";`)
Async/await is supported since 10.1; Core’s Promise
helpers keep chains tidy.
TS vs ReScript — What changes day‑to‑day?
Concern | TypeScript | ReScript |
---|---|---|
Type model | Structural (can mask errors) | Nominal + sound |
Nullability |
undefined /null , strict modes |
option everywhere |
Unions | Discriminated unions (verbose) | Variants + switch |
DX at scale | Good → can slow | Consistently fast |
Interop | Native JS | Via externals, still on NPM |
Output | Erases types | Readable JS, optimized layout |
Migration Checklist (pragmatic)
- [ ] Pick a leaf feature or route for the pilot.
- [ ] Add bindings only for functions you call.
- [ ] Replace string enums with
Variant
types. - [ ] Convert nullable data to
option
and match. - [ ] Adopt pipes & labeled args for clarity.
- [ ] Keep compiled JS in VCS during the pilot (easy rollback).
Deployment note: Leapcell (fits the vibe)
- Free unlimited projects; pay for usage only.
- Async tasks + Redis built in.
- Nice DX: CI/CD + GitOps, logs/metrics.
- Auto‑scale without ops — great for ReScript + React SSR/RSC.
Final word
If you’re happy in TS, you’ll still be happy tomorrow. If you want stronger guarantees with fewer footguns and faster feedback, ReScript is ready today — and it doesn’t ask you to leave the JS ecosystem to get there.
✍️ Written by Cristian Sifuentes — Full‑stack developer & AI/JS enthusiast focused on resilient frontends and scalable architectures.
Tags: #react #frontend #performance #ssr #architecture
Top comments (0)