English for ReScript Developers
Learn the English vocabulary for ReScript: variants, the type system, JavaScript interop, and pipe-first syntax.
ReScript conversations often need to draw a clear line between what the sound, ReScript-native type system guarantees and what happens the moment code crosses the boundary into untyped JavaScript — that boundary is where most real bugs and most real discussions live.
Key Vocabulary
Variant — a type representing one of a fixed set of named cases, each optionally carrying data, used instead of string literals or loosely-typed unions.
“Instead of a string status field that could be typo’d, we used a variant with Pending, Shipped, and Cancelled — the compiler now rejects invalid states entirely.”
Sound type system — ReScript’s guarantee that if the code compiles, the types are actually correct at runtime, unlike TypeScript’s type system which allows some unsound escape hatches. “We don’t need defensive null checks here — the sound type system guarantees this value can’t be undefined if the code compiled.”
Bindings (external) — hand-written type declarations that describe the shape of an existing JavaScript library or API to the ReScript compiler, since it can’t infer types from raw JS. “The crash happened because our binding for that JS library was slightly wrong — the type system trusted a declaration that didn’t match reality.”
Pipe-first (->) — an operator that passes the left-hand value as the first argument to the function on the right, used to chain transformations in a readable left-to-right order.
“Instead of nesting five function calls, we rewrote it as a -> pipe chain, and the transformation reads top to bottom the way it actually executes.”
Pattern matching (switch) — a switch expression over a variant that the compiler checks for exhaustiveness, ensuring every case, including new ones added later, gets handled.
“Adding the new Refunded variant broke the build in three places — that’s the compiler forcing us to update every switch that handles order status.”
Common Phrases
- “Is this a variant, or are we still passing around a raw string that could be misspelled?”
- “Can we trust the sound type system here, or does this value come from an external binding that might be wrong?”
- “Is our binding for this library accurate, or is that where the runtime mismatch is coming from?”
- “Should we rewrite this as a pipe chain for readability, or does the nested call actually read fine?”
- “Did this switch become non-exhaustive after adding the new variant — do we need to handle that case?”
Example Sentences
Explaining a type-safety win in review: “We modeled the payment state as a variant instead of a boolean pair, so ‘paid and refunded’ isn’t even a representable state anymore.”
Describing an interop issue: “The bug wasn’t in our logic — our binding claimed this callback always returns a value, but the actual JS library can return undefined.”
Justifying a refactor: “We switched this transformation to pipe-first syntax so new team members can read the data flow left to right instead of untangling nested calls.”
Professional Tips
- Prefer a variant over a string or boolean flag whenever the set of valid states is fixed and known — it makes invalid states unrepresentable.
- Treat a mismatched binding as the prime suspect whenever a runtime bug appears despite code that “should” be sound — the type system can only be as correct as the binding it trusts.
- Use pipe-first syntax deliberately for multi-step transformations, and say so in review — it’s a readability choice, not just a style preference.
- Welcome a broken exhaustive switch after adding a variant as useful feedback — it’s surfacing every place that needs to be updated.
Practice Exercise
- Explain why ReScript’s type system is described as “sound” while TypeScript’s is not fully sound.
- Describe what an external binding is and why an incorrect one can cause a runtime bug despite type-checking passing.
- Write a sentence justifying the use of a variant instead of a string field.
Bridging the Gap: Navigating Nuance for Non-Native Speakers
The core concepts of ReScript – its functional paradigm, its approach to type inference, and its seamless integration with JavaScript – are often readily grasped by developers regardless of their native language. However, successfully collaborating within a professional software development environment demands far more than just understanding the what; it requires mastering the how – specifically, how to communicate effectively through written documentation, code reviews, and team interactions. For non-native English speakers, this can feel particularly challenging due to subtle differences in phrasing, idiomatic expressions, and the expectations around clarity and precision inherent in technical communication. It’s not just about using the correct words; it’s about conveying intent and context with confidence. A seemingly minor change in wording can completely alter the meaning or impact of a comment, leading to confusion and wasted time. Let’s consider some common pitfalls and how to avoid them.
One key area is understanding feedback within code reviews. Receiving criticism – even constructive criticism – can be difficult for anyone, but when faced with unfamiliar phrasing, it’s crucial to actively seek clarification. Instead of simply reacting defensively (“I don’t understand this comment”), a more productive approach would be: “Could you elaborate on what you mean by ‘this could be improved’? Specifically, are there any potential performance implications I should consider?” This demonstrates engagement and a willingness to learn, fostering a more positive and collaborative review process. Similarly, crafting clear PR descriptions requires careful consideration of the audience – other developers who may not be intimately familiar with your specific code base or design choices. Detail is vital: don’t just state what you changed; explain why. Use phrases like “This refactoring improves readability by…” or “Introducing this feature allows us to…”.
Another frequently encountered situation involves discussing variants within ReScript’s type system. Explaining the nuances of variant definitions and their impact on type safety can be particularly challenging for those accustomed to different type systems. Using precise language is paramount: “This variant ensures that the function always returns a value of type string or number, preventing potential runtime errors if an unexpected type is passed.” Furthermore, when documenting decisions related to interop with JavaScript, it’s essential to articulate the rationale behind using specific JavaScript APIs and their corresponding ReScript types. “We’ve opted for this particular JavaScript library because it provides a more efficient way to handle asynchronous operations in our application.”
Finally, remember that concise communication is often valued over lengthy explanations. While thoroughness is appreciated, avoid unnecessary jargon or overly complex sentences. Aim for clarity above all else.
// Example using ReScript's type system for variants
// Illustrative - a simplified example to demonstrate the concept of variant types
type Result =
| { success: string }
| { failure: Error };
function processData(input: any): Result {
if (input) {
return { success: `Processed: ${input}` };
} else {
return { failure: new Error("Input is missing") };
}
}
console.log(processData(123)); // Output: { success: "Processed: 123" }
console.log(processData(null)); // Output: { failure: Error: Input is missing }