Skip to content

Adapt some pages to ReScript 11 including records and variants #730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 1 addition & 28 deletions pages/docs/manual/latest/function.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -388,34 +388,7 @@ function callFirst(_param) {

</CodeTab>

## Uncurried Function

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:

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

```res example
let add = (. x, y) => x + y

add(. 1, 2)
```
```js
function add(x, y) {
return x + y | 0;
}

add(1, 2);
```

</CodeTab>

If you write down the uncurried function's type, you'll add a dot there as well.

**Note**: both the declaration site and the call site need to have the uncurry annotation. That's part of the guarantee/requirement.

**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.

## Async/Await (from v10.1)
## Async/Await

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.
The output looks like idiomatic JS:
Expand Down
9 changes: 9 additions & 0 deletions pages/docs/manual/latest/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ npm run res:build
node src/Demo.bs.js
```

or use the create-rescript-app tool:

```sh
npm create rescript-app // Select basic template
cd <your-rescript-project-name>
npm run res:build
node src/Demo.bs.js
```

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!

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.
Expand Down
4 changes: 2 additions & 2 deletions pages/docs/manual/latest/let-binding.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ As a matter of fact, even this is valid code:

```res example
let result = "hello"
Js.log(result) // prints "hello"
Console.log(result) // prints "hello"
let result = 1
Js.log(result) // prints 1
Console.log(result) // prints 1
```
```js
var result = 1;
Expand Down
21 changes: 1 addition & 20 deletions pages/docs/manual/latest/primitive-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ There's a special syntax for string that allows
- multiline string just like before
- no special character escaping
- Interpolation
- Proper unicode handling

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

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

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

### Unsafe String Interpolation (Deprecated)

> ReScript v10.1.4 deprecated unsafe string interpolation and will be removed in v11.

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

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

```res example
let age = 10
let message = j`Today I am $age years old.`
```
```js
var message = "Today I am " + 10 + " years old.";
```

</CodeTab>

### Usage

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

### Tips & Tricks

Expand Down
117 changes: 117 additions & 0 deletions pages/docs/manual/latest/record.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,122 @@ var me = {

</CodeTab>

## Record Type Spread

In ReScript v11, you can now spread one or more record types into a new record type. It looks like this:

```rescript
type a = {
id: string,
name: string,
}

type b = {
age: int
}

type c = {
...a,
...b,
active: bool
}
```

`type c` will now be:

```rescript
type c = {
id: string,
name: string,
age: int,
active: bool,
}
```

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.

## Record Type Coercion

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:

```rescript
type a = {
name: string,
age: int,
}

type b = {
name: string,
age: int,
}

let nameFromB = (b: b) => b.name

let a: a = {
name: "Name",
age: 35,
}

let name = nameFromB(a :> b)
```

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.

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:

```rescript
type a = {
id: string,
name: string,
age: int,
active: bool,
}

type b = {
name: string,
age: int,
}

let nameFromB = (b: b) => b.name

let a: a = {
id: "1",
name: "Name",
age: 35,
active: true,
}

let name = nameFromB(a :> b)
```

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`.

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:

```rescript
type a = {
name: string,

// mandatory, but explicitly typed as option<int>
age: option<int>,
}

type b = {
name: string,
// optional field
age?: int,
}

let nameFromB = (b: b) => b.name

let a: a = {
name: "Name",
age: Some(35),
}

let name = nameFromB(a :> b)
```

## Tips & Tricks

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

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

Loading