Skip to content

Commit 959daba

Browse files
fhammerschmidtzth
authored andcommitted
Adapt some pages to ReScript 11 including records and variants (#730)
* Adapt some pages to ReScript 11 including records and variants * Some better wordings * Variants: Add some TODOs
1 parent 78bc6b5 commit 959daba

File tree

6 files changed

+419
-66
lines changed

6 files changed

+419
-66
lines changed

pages/docs/manual/latest/function.mdx

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -388,34 +388,7 @@ function callFirst(_param) {
388388

389389
</CodeTab>
390390

391-
## Uncurried Function
392-
393-
ReScript's functions are curried by default, which is one of the few performance penalties we pay in the compiled JS output. The compiler does a best-effort job at removing those currying whenever possible. However, in certain edge cases, you might want guaranteed uncurrying. In those cases, put a dot in the function's parameter list:
394-
395-
<CodeTab labels={["ReScript", "JS Output"]}>
396-
397-
```res example
398-
let add = (. x, y) => x + y
399-
400-
add(. 1, 2)
401-
```
402-
```js
403-
function add(x, y) {
404-
return x + y | 0;
405-
}
406-
407-
add(1, 2);
408-
```
409-
410-
</CodeTab>
411-
412-
If you write down the uncurried function's type, you'll add a dot there as well.
413-
414-
**Note**: both the declaration site and the call site need to have the uncurry annotation. That's part of the guarantee/requirement.
415-
416-
**This feature seems trivial**, but is actually one of our most important features, as a primarily functional language. We encourage you to use it if you'd like to remove any mention of `Curry` runtime in the JS output.
417-
418-
## Async/Await (from v10.1)
391+
## Async/Await
419392

420393
Just as in JS, an async function can be declared by adding `async` before the definition, and `await` can be used in the body of such functions.
421394
The output looks like idiomatic JS:

pages/docs/manual/latest/installation.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ npm run res:build
2121
node src/Demo.bs.js
2222
```
2323

24+
or use the create-rescript-app tool:
25+
26+
```sh
27+
npm create rescript-app // Select basic template
28+
cd <your-rescript-project-name>
29+
npm run res:build
30+
node src/Demo.bs.js
31+
```
32+
2433
That compiles your ReScript into JavaScript, then uses Node.js to run said JavaScript. **We recommend you use our unique workflow of keeping a tab open for the generated `.bs.js` file**, so that you can learn how ReScript transforms into JavaScript. Not many languages output clean JavaScript code you can inspect and learn from!
2534

2635
During development, instead of running `npm run res:build` each time to compile, use `npm run res:dev` to start a watcher that recompiles automatically after file changes.

pages/docs/manual/latest/let-binding.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,9 @@ As a matter of fact, even this is valid code:
131131

132132
```res example
133133
let result = "hello"
134-
Js.log(result) // prints "hello"
134+
Console.log(result) // prints "hello"
135135
let result = 1
136-
Js.log(result) // prints 1
136+
Console.log(result) // prints 1
137137
```
138138
```js
139139
var result = 1;

pages/docs/manual/latest/primitive-types.mdx

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ There's a special syntax for string that allows
4848
- multiline string just like before
4949
- no special character escaping
5050
- Interpolation
51-
- Proper unicode handling
5251

5352
<CodeTab labels={["ReScript", "JS Output"]}>
5453

@@ -71,27 +70,9 @@ var greeting = "Hello\nWorld\n👋\n" + name + "\n";
7170

7271
This is just like JavaScript's backtick string interpolation, except without needing to escape special characters.
7372

74-
### Unsafe String Interpolation (Deprecated)
75-
76-
> ReScript v10.1.4 deprecated unsafe string interpolation and will be removed in v11.
77-
78-
For interpolation, you'll have to convert the binding (`name` in the example) into a string if it isn't one. If you want the interpolation to implicitly convert a binding into a string, prepend a `j`:
79-
80-
<CodeTab labels={["ReScript", "JS Output"]}>
81-
82-
```res example
83-
let age = 10
84-
let message = j`Today I am $age years old.`
85-
```
86-
```js
87-
var message = "Today I am " + 10 + " years old.";
88-
```
89-
90-
</CodeTab>
91-
9273
### Usage
9374

94-
See the familiar `Js.String` API in the [API docs](api/js/string). Since a ReScript string maps to a JavaScript string, you can mix & match the string operations in both standard libraries.
75+
See the familiar `String` API in the [API docs](api/js/string). Since a ReScript string maps to a JavaScript string, you can mix & match the string operations in all standard libraries.
9576

9677
### Tips & Tricks
9778

pages/docs/manual/latest/record.mdx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,122 @@ var me = {
394394

395395
</CodeTab>
396396

397+
## Record Type Spread
398+
399+
In ReScript v11, you can now spread one or more record types into a new record type. It looks like this:
400+
401+
```rescript
402+
type a = {
403+
id: string,
404+
name: string,
405+
}
406+
407+
type b = {
408+
age: int
409+
}
410+
411+
type c = {
412+
...a,
413+
...b,
414+
active: bool
415+
}
416+
```
417+
418+
`type c` will now be:
419+
420+
```rescript
421+
type c = {
422+
id: string,
423+
name: string,
424+
age: int,
425+
active: bool,
426+
}
427+
```
428+
429+
Record type spreads act as a 'copy-paste' mechanism for fields from one or more records into a new record. This operation inlines the fields from the spread records directly into the new record definition, while preserving their original properties, such as whether they are optional or mandatory. It's important to note that duplicate field names are not allowed across the records being spread, even if the fields have the same type.
430+
431+
## Record Type Coercion
432+
433+
Record type coercion gives us more flexibility when passing around records in our application code. In other words, we can now coerce a record `a` to be treated as a record `b` at the type level, as long as the original record `a` contains the same set of fields in `b`. Here's an example:
434+
435+
```rescript
436+
type a = {
437+
name: string,
438+
age: int,
439+
}
440+
441+
type b = {
442+
name: string,
443+
age: int,
444+
}
445+
446+
let nameFromB = (b: b) => b.name
447+
448+
let a: a = {
449+
name: "Name",
450+
age: 35,
451+
}
452+
453+
let name = nameFromB(a :> b)
454+
```
455+
456+
Notice how we _coerced_ the value `a` to type `b` using the coercion operator `:>`. This works because they have the same record fields. This is purely at the type level, and does not involve any runtime operations.
457+
458+
Additionally, we can also coerce records from `a` to `b` whenever `a` is a super-set of `b` (i.e. `a` containing all the fields of `b`, and more). The same example as above, slightly altered:
459+
460+
```rescript
461+
type a = {
462+
id: string,
463+
name: string,
464+
age: int,
465+
active: bool,
466+
}
467+
468+
type b = {
469+
name: string,
470+
age: int,
471+
}
472+
473+
let nameFromB = (b: b) => b.name
474+
475+
let a: a = {
476+
id: "1",
477+
name: "Name",
478+
age: 35,
479+
active: true,
480+
}
481+
482+
let name = nameFromB(a :> b)
483+
```
484+
485+
Notice how `a` now has more fields than `b`, but we can still coerce `a` to `b` because `b` has a subset of the fields of `a`.
486+
487+
In combination with [optional record fields](/docs/manual/latest/record#optional-record-fields), one may coerce a mandatory field of an `option` type to an optional field:
488+
489+
```rescript
490+
type a = {
491+
name: string,
492+
493+
// mandatory, but explicitly typed as option<int>
494+
age: option<int>,
495+
}
496+
497+
type b = {
498+
name: string,
499+
// optional field
500+
age?: int,
501+
}
502+
503+
let nameFromB = (b: b) => b.name
504+
505+
let a: a = {
506+
name: "Name",
507+
age: Some(35),
508+
}
509+
510+
let name = nameFromB(a :> b)
511+
```
512+
397513
## Tips & Tricks
398514

399515
### Record Types Are Found By Field Name
@@ -438,3 +554,4 @@ After reading the constraints in the previous sections, and if you're coming fro
438554

439555
1. The truth is that most of the times in your app, your data's shape is actually fixed, and if it's not, it can potentially be better represented as a combination of variant (introduced next) + record instead.
440556
2. Since a record type is resolved through finding that single explicit type declaration (we call this "nominal typing"), the type error messages end up better than the counterpart ("structural typing", like for tuples). This makes refactoring easier; changing a record type's fields naturally allows the compiler to know that it's still the same record, just misused in some places. Otherwise, under structural typing, it might get hard to tell whether the definition site or the usage site is wrong.
557+

0 commit comments

Comments
 (0)