Can folks share what they are using for rules files in “developer copilot” enabled IDEs like Cursor, Windsurf, etc… Anybody found anything helpful beyond the non-rule based interactions?
I had these rules a while ago in Cursor:
- You use the latest ReScript v12 alpha.
- Ensure suggestions match this version. Refer to the indexed ReScript manual.
- Ensure any produced JSX matches the ReScript JSX syntax.
- Never ever use the `Belt` or `Js` modules, these are legacy.
- Always use the `JSON.t` type for json.
- Module with React components do require a signature file (`.resi`) for Vite HMR to work.
Only the React components can be exposed from the javascript.
- In ReScript you cannot add text as child of a react component directly.
`<h1 className="text-4xl font-bold mb-4">404 - Page Not Found</h1>` is wrong. The parser does not accept this.
It should be `<h1 className="text-4xl font-bold mb-4">{React.string("404 - Page Not Found")}</h1>`.
Everything should be a `React.element` in ReScript. So you need to use primitive conversion functions like `React.string`, `React.int`, `React.float` & `React.array`.
- When dealing with promises, prefer using `async/await` syntax.
- `React.useState` in ReScript takes a function when invoked. `let (age, setAge) = React.useState(_ => 4)`
- Every expression inside an interpolated string is expected to be of type string. You can't do `\`age = ${42}\``.
You need to convert that number to a string. `\`age = ${(42)->Int.toString}\``
- In ReScript `type` is a keyword, so it can't be used a prop name in a JSX prop. Use `type_` if you need it. For example `<button type_="Submit"></button>`
7 Likes
Thank you - always good to have a head start!
1 Like
I can’t seem to edit my answer, so posting my recent list here again:
- You use the latest ReScript v12 rc.
- Ensure suggestions match this version. Refer to the indexed ReScript manual.
- Ensure any produced JSX matches the ReScript JSX syntax.
- Never ever use the
Belt
orJs
modules, these are legacy. - Always use the
JSON.t
type for json. - Module with React components do require a signature file (
.resi
) for Vite HMR to work.
Only the React components can be exposed from the javascript. - In ReScript you cannot add text as child of a react component directly.
<h1 className="text-4xl font-bold mb-4">404 - Page Not Found</h1>
is wrong. The parser does not accept this.
It should be<h1 className="text-4xl font-bold mb-4">{React.string("404 - Page Not Found")}</h1>
.
Everything should be aReact.element
in ReScript. So you need to use primitive conversion functions likeReact.string
,React.int
,React.float
&React.array
. - When dealing with promises, prefer using
async/await
syntax. -
React.useState
in ReScript takes a function when invoked.let (age, setAge) = React.useState(_ => 4)
- We are using the jsx preserve mode, meaning our output JavaScript file will have JSX.
Although this looks quite machine generated. - Every expression inside an interpolated string is expected to be of type string. You can’t do
\
age = ${42}`. You need to convert that number to a string.
`age = ${(42)->Int.toString}`` - In ReScript
type
is a keyword, so it can’t be used a prop name in a JSX prop. Usetype_
if you need it. For example<button type_="Submit"></button>
- There are global helpers defined in src/Iluvatar.res, these should always be used when possible. No need to
open Iluvatar
, this is done in viarescript.json
. (project specific) - External bindings with
@send
that return a value do not require()
to be invoked.
type t
@send
external foo: t => string = "foo"
external i: t = "t"
let b = i->foo // Notice no `()` here!
- When you see
include
in ReScript source code, it means a module function was used. This brings additional symbols into the current module scope that aren’t visible in the original source. - ReScript uses namespaces (defined in
rescript.json
) to solve module naming conflicts. Since ReScript only allows one module name per project, namespaces let you have modules with the same name in different folders. In code, namespaces look likeMyNamespace.MyModule.myType
, but internally they’re stored asMyModule-MyNamespace.myType
during compilation. - ReScript does not support F#-style generic type parameters, either on the definition or the calling side.
You can’t writelet id<'a> = x => x
or call functions likeid<int>(5)
.
Generics are always inferred automatically by the compiler.
If you want to type a binding, put the type annotation after the pattern, not as a generic.
For example:
// ✅ Correct
let id: int => int = x => x
// ❌ Wrong (F# style)
let id<'a> = x => x
let y = id<int>(5)
3 Likes