You are currently looking at the v6.0 - v8.2 docs (Reason v3.6 syntax edition). You can find the latest manual page here.
(These docs are equivalent to the old BuckleScript docs before the ReScript rebrand)
Use Illegal Identifier Names
This page is solely dedicated to Reason v3.6 related naming collisions and also highlights some name mangling rules the ReScript compiler implemented just for Reason purposes.
JavaScript has different naming conventions and has only very few limitations when it comes to naming variables, classes, functions, JS object attributes etc.
Reason on the contrary has more restrictive naming rules which need to be considered whenever you define a type, function, value, module, record attribute or similar. Here are a few typical naming restrictions which cause trouble with JS:
Every name needs to start with a lowercase letter (uppercase is reserved for module names)
For the same reason, names can't be all caps (very common for JS constants:
const MY_CONSTANT = "my_constant"
)It's not possible to use reserved keywords for names
Labeled arguments (for defining JSX attributes) can't be named after keywords and can't start with an uppercase letter
etc.
Of course, when doing interop, we still want to be able to map to the JS equivalent (preferably without any runtime overhead). In this section we describe some common scenarios on how to gracefully handle naming collisions.
Using reserved keywords as JSX props
Many React components have a prop named type
in JavaScript:
JS/* this won't work in Reason since `type` is a reserved keyword! */
<Component type="title" />
If you're using a React component with a reserved keyword as a prop name, then simply prepend a underscore (so that it's a valid Reason name):
/* This works because `_type` is not a reserved keyword */
<Component _type="title" />
The Reason compiler will remove the leading underscore when outputting JavaScript (so the JavaScript will have <Component type="POST" />
).
The removal of the _
is called "Name mangling". The ruleset for this behavior is discussed further down below.
Accessing JavaScript object attributes that start with a capital letter
Capital letters in Reason are used exclusively for module names, like String
and Belt
, and they cannot be used as record field names like in JavaScript.
JSconst payload = {
PostTitle: "Welcome to Reason",
};
/* this won't work in Reason since `PostTitle` is capitalized, so `paylod.PostTitle` would break */
const title = payload.PostTitle;
In this case, when writing bindings to the JavaScript object, you can use the [@bs.as "whatever-name-you-want-in-javascript"]
to tell the compiler exactly what the JavaScript attribute name should be in the compiled output:
type payload = {
[@bs.as "PostTitle"] postTitle: string
};
let payload = {
postTitle: "Welcome to Reason"
};
/* ReScript is happy since we're using the valid `postTitle` field name */
let title = payload.postTitle;
Accessing reserved keywords as JavaScript object attribute names
Just like accessing attributes that start with a capital letter, we can use [@bs.as "the-reserved-keyword-that-javascript-wants"]
. It's customary to append an underscore (unlike the JSX case, where we prepend the underscore) to the reserved keyword name:
type payload = {
[@bs.as "type"] type_: string
}
let payload = {
type_: "Documentation"
}
/* ReScript is happy since we're using the valid `type_` field name */
let payloadType = payload.type_;
Special name mangling rules for JS object attribute names
Note: This is special behavior partly implemented in the Reason syntax, partly in the ReScript compiler. This section is mostly useful for understanding how JS object attributes and labeled arguments of ReasonReact components are compiled.
Another Note: A JS object type is a structurally typed entity with special compilation behavior, so they act differently than records or plain Reason objects. They are encoded as
Js.t({...})
types, more details about that feature can be found here.Labeled arguments used in
[@react.component]
functions (likelet make = (~name: string, ~age: int) => React.element
) are transformed into theJs.t
representation (e.g.let make = Js.t({."name": string, "age": int}) => React.element
), so they follow the same ruleset.
When accessing a JavaScript object field in a structural way (e.g. myJsObject##some
), the following rules apply:
A single leading underscore will be dropped from the output:
myJsObject##_type
=>myJsObject.type
Two (or more) leading underscores will be kept in the output:
myJsObject##__type
=>myJsObject.__type
There is no way to access e.g.
myJsObject##_type
structurally - use records and[@bs.as "_type"]
insteadThe final trailing double underscores (and anything following them) will be dropped from the output:
myJsObject##this_is_kept__this_is_omitted
=>myJsObject.this_is_kept