Skip to content

Commit 7b696f9

Browse files
committed
Update record and variant pages with js output
1 parent aa1460f commit 7b696f9

File tree

2 files changed

+110
-12
lines changed

2 files changed

+110
-12
lines changed

pages/docs/manual/latest/record.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ baby.age = baby.age + 1 | 0;
151151

152152
</CodeTab>
153153

154+
Fields not marked with `mutable` in the type declaration cannot be mutated.
155+
156+
## JavaScript Output
157+
158+
ReScript records compile to straightforward JavaScript objects; see the various JS output tabs above.
159+
154160
## Tips & Tricks
155161

156162
**Record Types Are Found By Field Name**. With records, you **cannot** say "I'd like this function to take any record type, as long as they have the field `age`". The following **won't work as intended**:

pages/docs/manual/latest/variant.mdx

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,44 +101,136 @@ var friendAccount = {
101101

102102
</CodeTab>
103103

104-
### Records in Variants
104+
### Labeled Variant Payloads (Inline Record)
105105

106-
You can use a record type in a variant:
106+
If a variant payload has multiple fields, you can use a record-like syntax to label them for better readability:
107107

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

110110
```res example
111-
type idType = {name: string, password: string}
112-
113111
type user =
114112
| Number(int)
115-
| Id(idType)
113+
| Id({name: string, password: string})
114+
115+
let me = Id({name: "Joe", password: "123"})
116116
```
117117
```js
118-
// Empty output
118+
var me = {
119+
TAG: /* Id */1,
120+
name: "Joe",
121+
password: "123"
122+
};
119123
```
120124

121125
</CodeTab>
122126

123-
If the record type is used only in the variant definition, you may put it in line:
127+
This is technically called an "inline record", and only allowed within a variant constructor. You cannot inline a record type declaration anywhere else in ReScript.
128+
129+
Of course, you can just put a regular record type in a variant too:
124130

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

127133
```res example
134+
type u = {name: string, password: string}
128135
type user =
129136
| Number(int)
130-
| Id({name: string, password: string})
137+
| Id(u)
138+
139+
let me = Id({name: "Joe", password: "123"})
131140
```
132141
```js
133-
// Empty output
142+
var me = {
143+
TAG: /* Id */1,
144+
_0: {
145+
name: "Joe",
146+
password: "123"
147+
}
148+
};
134149
```
135150

136151
</CodeTab>
137152

153+
The output is slightly uglier and less performant than the former.
154+
138155
### Pattern Matching On Variant
139156

140157
See the [Pattern Matching/Destructuring](pattern-matching-destructuring.md) section later.
141158

159+
## JavaScript Output
160+
161+
A variant value compiles to 3 possible JavaScript outputs depending on its type declaration:
162+
163+
- If the variant value is a constructor with no payload, it compiles to a number.
164+
- If it's a constructor with a payload, it compiles to an object with the field `TAG` and the field `_0` for the first payload, `_1` for the second payload, etc.
165+
- An exception to the above is a variant whose type declaration contains only a single constructor with payload. In that case, the constructor compiles to an object without the `TAG` field.
166+
- Labeled variant payloads (the inline record trick earlier) compile to an object with the label names instead of `_0`, `_1`, etc. The object might or might not have the `TAG` field as per previous rule.
167+
168+
Check the output in these examples:
169+
170+
<CodeTab labels={["ReScript", "JS Output"]}>
171+
172+
```res example
173+
type greeting = Hello | Goodbye
174+
let g1 = Hello
175+
let g2 = Goodbye
176+
177+
type outcome = Good | Error(string)
178+
let o1 = Good
179+
let o2 = Error("oops!")
180+
181+
type family = Child | Mom(int, string) | Dad (int)
182+
let f1 = Child
183+
let f2 = Mom(30, "Jane")
184+
let f3 = Dad(32)
185+
186+
type person = Teacher | Student({gpa: float})
187+
let p1 = Teacher
188+
let p2 = Student({gpa: 99.5})
189+
190+
type s = {score: float}
191+
type adventurer = Warrior(s) | Wizard(string)
192+
let a1 = Warrior({score: 10.5})
193+
let a2 = Wizard("Joe")
194+
```
195+
```js
196+
var g1 = /* Hello */0;
197+
var g2 = /* Goodbye */1;
198+
199+
var o1 = /* Good */0;
200+
var o2 = /* Error */{
201+
_0: "oops!"
202+
};
203+
204+
var f1 = /* Child */0;
205+
var f2 = {
206+
TAG: /* Mom */0,
207+
_0: 30,
208+
_1: "Jane"
209+
};
210+
var f3 = {
211+
TAG: /* Dad */1,
212+
_0: 32
213+
};
214+
215+
var p1 = /* Teacher */0;
216+
var p2 = /* Student */{
217+
gpa: 99.5
218+
};
219+
220+
var a1 = {
221+
TAG: /* Warrior */0,
222+
_0: {
223+
score: 10.5
224+
}
225+
};
226+
var a2 = {
227+
TAG: /* Wizard */1,
228+
_0: "Joe"
229+
};
230+
```
231+
232+
</CodeTab>
233+
142234
## Tips & Tricks
143235

144236
**Be careful** not to confuse a constructor carrying 2 arguments with a constructor carrying a single tuple argument:
@@ -155,10 +247,10 @@ type account2 =
155247
// Empty output
156248
```
157249

158-
### Variants Must Have Constructors
159-
160250
</CodeTab>
161251

252+
### Variants Must Have Constructors
253+
162254
If you come from an untyped language, you might be tempted to try `type myType = int | string`. This isn't possible in ReScript; you'd have to give each branch a constructor: `type myType = Int(int) | String(string)`. The former looks nice, but causes lots of trouble down the line.
163255

164256
### Interop with JavaScript
@@ -200,7 +292,7 @@ betterDraw({
200292

201293
</CodeTab>
202294

203-
You could definitely do that, but there are better ways! For example, define two `external`s that both compile to the same JS call:
295+
**Try not to do that**, as this generates extra noisy output. Alternatively, define two `external`s that both compile to the same JS call:
204296

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

0 commit comments

Comments
 (0)