Quick Links
  • -Overview
  • -Language Features
  • -JS Interop
  • -Build System
Documentation
Language Manual
Reference for all language features
ReScript & React
First class bindings for ReactJS
GenType
Seamless TypeScript integration
Reanalyze
Dead Code & Termination analysis
Exploration
Packages
Explore third party libraries and bindings
Syntax Lookup
Discover all syntax constructs
APIPlaygroundBlogCommunity
  • Playground
  • Blog
  • Twitter
  • GitHub
  • Forum
Language Manual
Overview
  • Introduction
  • Installation
  • Editor Plugins
  • Migrate to ReScript Syntax
  • Try
Language Features
  • Overview
  • Let Binding
  • Type
  • Primitive Types
  • Tuple
  • Record
  • Object
  • Variant
  • Null, Undefined and Option
  • Array & List
  • Function
  • If-Else & Loops
  • Pipe
  • Pattern Matching / Destructuring
  • Mutation
  • JSX
  • Exception
  • Lazy Values
  • Promise
  • Module
  • Import & Export
  • Reserved Keyword
JavaScript Interop
  • Embed Raw JavaScript
  • Shared Data Types
  • External (Bind to Any JS Library)
  • Bind to JS Object
  • Bind to JS Function
  • Import from / Export to JS
  • Bind to Global JS Values
  • JSON
  • Use Illegal Identifier Names
    • Using reserved keywords as JSX props
    • Accessing JavaScript object attributes that start with a capital letter
    • Accessing reserved keywords as JavaScript object attribute names
    • Special name mangling rules for JS object attribute names
  • Generate Converters & Helpers
  • Browser Support & Polyfills
  • Interop Cheatsheet
Build System
  • Build System Overview
  • Build System Configuration
  • Interop with JS Build Systems
  • Build Performance
Guides
  • Converting from JS
  • Libraries
Extra
  • Newcomer Examples
  • Project Structure
  • FAQ
Docs / Language Manual / Use Illegal Identifier Names
Edit

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):

Reason (Old Syntax)ML (Older Syntax)
/* 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.

JS
const 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:

Reason (Old Syntax)ML (Older Syntax)JS 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:

Reason (Old Syntax)ML (Older Syntax)JS Output
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 (like let make = (~name: string, ~age: int) => React.element) are transformed into the Js.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:

  1. A single leading underscore will be dropped from the output: myJsObject##_type => myJsObject.type

  2. Two (or more) leading underscores will be kept in the output: myJsObject##__type => myJsObject.__type

  3. There is no way to access e.g. myJsObject##_type structurally - use records and [@bs.as "_type"] instead

  4. The 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

JSONGenerate Converters & Helpers

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on