You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Note:** In a practical scenario you'd either use a type signature, or inline types, not both at the same time. In case you are interested in the design decisions, check out [this discussion](https://github.com/rescript-lang/rescript-compiler/pull/5913#issuecomment-1359003870).
115
113
116
-
### `async` uncurried functions
117
-
118
-
The `async` keyword does also work for uncurried functions.
119
-
120
-
```res
121
-
let fetchData = async (. userId: string): string {
122
-
await fetchUserMail(userId)
123
-
}
124
-
```
125
-
126
114
### Promises don't auto-collapse in async functions
127
115
128
116
In JS, nested promises (i.e. `promise<promise<'a>>`) will automatically collapse into a flat promise (`promise<'a>`). This is not the case in ReScript. Use the `await` function to manually unwrap any nested promises within an `async` function instead.
We've compiled to the same function, but now the usage is much clearer on the ReScript side thanks to labels!
62
62
63
-
**Note**: in this particular case, you need a unit, `()` after `border`, since `border` is an [optional argument at the last position](function.md#optional-labeled-arguments). Not having a unit to indicate you've finished applying the function would generate a warning.
64
-
65
63
Note that you can freely reorder the labels on the ReScript side; they'll always correctly appear in their declaration order in the JavaScript output:
**Note:** It's a pretty niche feature, mostly used to map to polymorphic JS APIs.
350
348
351
-
352
-
## Curry & Uncurry
353
-
354
-
Curry is a delicious Indian dish. More importantly, in the context of ReScript (and functional programming in general), currying means that function taking multiple arguments can be applied a few arguments at time, until all the arguments are applied.
355
-
356
-
See the `addFive` intermediate function? `add` takes in 3 arguments but received only 1. It's interpreted as "currying" the argument `5` and waiting for the next 2 arguments to be applied later on. Type signatures:
357
-
358
-
```res sig
359
-
let add: (int, int, int) => int
360
-
let addFive: (int, int) => int
361
-
let twelve: int
362
-
```
363
-
364
-
(In a dynamic language such as JS, currying would be dangerous, since accidentally forgetting to pass an argument doesn't error at compile time).
365
-
366
-
### Drawback
367
-
368
-
Unfortunately, due to JS not having currying because of the aforementioned reason, it's hard for ReScript multi-argument functions to map cleanly to JS functions 100% of the time:
369
-
370
-
1. When all the arguments of a function are supplied (aka no currying), ReScript does its best to to compile e.g. a 3-arguments call into a plain JS call with 3 arguments.
371
-
372
-
2. If it's too hard to detect whether a function application is complete\*, ReScript will use a runtime mechanism (the `Curry` module) to curry as many args as we can and check whether the result is fully applied.
373
-
374
-
3. Some JS APIs like `throttle`, `debounce` and `promise` might mess with context, aka use the function `bind` mechanism, carry around `this`, etc. Such implementation clashes with the previous currying logic.
375
-
376
-
\* If the call site is typed as having 3 arguments, we sometimes don't know whether it's a function that's being curried, or if the original one indeed has only 3 arguments.
377
-
378
-
ReScript tries to do #1 as much as it can. Even when it bails and uses #2's currying mechanism, it's usually harmless.
379
-
380
-
**However**, if you encounter #3, heuristics are not good enough: you need a guaranteed way of fully applying a function, without intermediate currying steps. We provide such guarantee through the use of the ["uncurrying" syntax](./function#uncurried-function) on a function declaration & call site.
381
-
382
-
### Solution: Use Guaranteed Uncurrying
383
-
384
-
[Uncurried function](function.md#uncurried-function) annotation also works on `external`:
In general, `uncurry` is recommended; the compiler will do lots of optimizations to resolve the currying to uncurrying at compile time. However, there are some cases the compiler can't optimize it. In these cases, it will be converted to a runtime check.
427
-
428
349
## Modeling `this`-based Callbacks
429
350
430
351
Many JS libraries have callbacks which rely on this (the source), for example:
`rescript.json` (or `rescript.json` in versions prior ReScript 11) is the single, mandatory build meta file needed for `rescript`.
10
+
`rescript.json` (or `bsconfig.json` in versions prior ReScript 11) is the single, mandatory build meta file needed for `rescript`.
11
11
12
12
**The complete configuration schema is [here](./build-configuration-schema)**. We'll _non-exhaustively_ highlight the important parts in prose below.
13
13
@@ -96,19 +96,6 @@ This is useful for working on multiple independent ReScript packages simultaneou
96
96
97
97
More details can be found on our [external stdlib](./build-external-stdlib) page.
98
98
99
-
## reason, refmt (old)
100
-
101
-
`reason` config is enabled by default. To turn on JSX for [ReasonReact](https://reasonml.github.io/reason-react/), specify:
102
-
103
-
```json
104
-
{
105
-
"reason": {"react-jsx": 3},
106
-
"refmt": 3
107
-
}
108
-
```
109
-
110
-
The `refmt` config **should be explicitly specified** as `3`.
111
-
112
99
## js-post-build
113
100
114
101
Hook that's invoked every time a file is recompiled. Good for JS build system interop, but please use it **sparingly**. Calling your custom command for every recompiled file slows down your build and worsens the building experience for even third-party users of your lib.
@@ -152,7 +139,19 @@ This configuration only applies to you, when you develop the project. When the p
152
139
153
140
## suffix
154
141
155
-
Either `".js"`, `".mjs"`, `".cjs"` or `".bs.js"`. Currently prefer `bs.js` for now.
142
+
**Since 11.0**: The suffix can now be freely chosen. However, we still suggest you stick to the convention and use
143
+
one of the following:
144
+
-`".js`
145
+
-`".mjs"`
146
+
-`".cjs"`
147
+
-`".res.js"`
148
+
-`".res.mjs"`
149
+
-`".res.cjs"`
150
+
-`".bs.js"`
151
+
-`".bs.mjs"`
152
+
-`".bs.cjs"`
153
+
154
+
Currently prefer `.bs.js` for now.
156
155
157
156
### Design Decisions
158
157
@@ -163,6 +162,18 @@ Generating JS files with the `.bs.js` suffix means that, on the JS side, you can
163
162
- It avoids the need of using a build system loader for ReScript files. This + in-source build means integrating a ReScript project into your pure JS codebase **basically doesn't touch anything in your build pipeline at all**.
164
163
-[genType](/docs/gentype/latest/introduction) requires `bs.js` for compiled JS artifacts. If you are using `genType`, you need to use `bs.js` for now.
165
164
165
+
## uncurried
166
+
167
+
**Since 11.0**: While we strongly encourage all users to use uncurried mode, it is still possible to opt out. Just set `"uncurried"` to `false` to get the old behavior back:
168
+
169
+
```json
170
+
{
171
+
"uncurried": false
172
+
}
173
+
```
174
+
175
+
More details can be found in the [blogpost about "Uncurried Mode"](/blog/uncurried-mode).
176
+
166
177
## warnings
167
178
168
179
Selectively turn on/off certain warnings and/or turn them into hard errors. Example:
var Caml_option =require("./stdlib/caml_option.js");
193
193
194
-
functiondrawCircle(color, radius, param) {
194
+
functiondrawCircle(color, radius) {
195
195
setColor(color);
196
196
if (radius ===undefined) {
197
197
returnstartAt(1, 1);
@@ -207,8 +207,6 @@ When given in this syntax, `radius` is **wrapped** in the standard library's `op
207
207
208
208
More on `option` type [here](null-undefined-option.md).
209
209
210
-
**Note** for the sake of the type system, whenever you have an optional argument, you need to ensure that there's also at least one positional argument (aka non-labeled, non-optional argument) after it. If there's none, provide a dummy `unit` (aka `()`) argument.
211
-
212
210
### Signatures and Type Annotations
213
211
214
212
Functions with optional labeled arguments can be confusing when it comes to signature and type annotations. Indeed, the type of an optional labeled argument looks different depending on whether you're calling the function, or working inside the function body. Outside the function, a raw value is either passed in (`int`, for example), or left off entirely. Inside the function, the parameter is always there, but its value is an option (`option<int>`). This means that the type signature is different, depending on whether you're writing out the function type, or the parameter type annotation. The first being a raw value, and the second being an option.
@@ -218,8 +216,8 @@ If we get back to our previous example and both add a signature and type annotat
218
216
<CodeTablabels={["ReScript", "JS Output"]}>
219
217
220
218
```res
221
-
let drawCircle: (~color: color, ~radius: int=?, unit) => unit =
222
-
(~color: color, ~radius: option<int>=?, ()) => {
219
+
let drawCircle: (~color: color, ~radius: int=?) => unit =
220
+
(~color: color, ~radius: option<int>=?) => {
223
221
setColor(color)
224
222
switch radius {
225
223
| None => startAt(1, 1)
@@ -228,7 +226,7 @@ let drawCircle: (~color: color, ~radius: int=?, unit) => unit =
228
226
}
229
227
```
230
228
```js
231
-
functiondrawCircle(color, radius, param) {
229
+
functiondrawCircle(color, radius) {
232
230
setColor(color);
233
231
if (radius !==undefined) {
234
232
returnstartAt(radius, radius);
@@ -255,16 +253,16 @@ Sometimes, you might want to forward a value to a function without knowing wheth
0 commit comments