Skip to content

Commit 37fcc8f

Browse files
committed
document how to define tag functions in rescript
1 parent 380a860 commit 37fcc8f

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

data/sidebar_manual_latest.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"lazy-values",
2929
"promise",
3030
"async-await",
31+
"tagged-templates",
3132
"module",
3233
"import-export",
3334
"attribute",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
---
2+
title: "Tagged templates"
3+
description: "Using tagged templates in ReScript"
4+
canonical: "/docs/manual/latest/tagged-templates"
5+
---
6+
7+
# Tagged templates
8+
9+
**Since 11.1**
10+
11+
Tagged templates provide a special form of string interpolation, enabling the creation of template literals
12+
where placeholders aren't restricted to strings. Moreover, the resulting output isn't confined solely to
13+
strings either. You can take a look at the [JS documentation
14+
about tagged templates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates)
15+
to learn more about them.
16+
17+
## Define a tag function
18+
19+
Tag functions in ReScript have the following signature:
20+
```res
21+
let myTagFunction : (array<string>, array<'param>) => 'output
22+
```
23+
As you can see, you can have any type you want both for the placeholder array and for the output.
24+
25+
Given how string interpolation works, you'll always have the following invariant:
26+
```res
27+
Array.length(strings) == Array.length(placeholder) + 1
28+
```
29+
30+
Let's say you want to interpolate strings with all kind of builtin types and make it work inside React components,
31+
you can define the following tag function:
32+
33+
<CodeTab labels={["ReScript", "JS Output"]}>
34+
35+
```res prelude
36+
type params =
37+
| I(int)
38+
| F(float)
39+
| S(string)
40+
| Bool(bool)
41+
42+
let s = (strings, parameters) => {
43+
let text = Array.reduceWithIndex(parameters, Array.getUnsafe(strings, 0), (
44+
acc,
45+
param,
46+
i,
47+
) => {
48+
let s = Array.getUnsafe(strings, i + 1)
49+
let p = switch param {
50+
| I(i) => Int.toString(i)
51+
| F(f) => Float.toString(f)
52+
| S(s) => s
53+
| Bool(true) => "true"
54+
| Bool(false) => "false"
55+
}
56+
acc ++ p ++ s
57+
})
58+
React.string(text)
59+
}
60+
```
61+
```js
62+
import * as Core__Array from "./stdlib/core__Array.js";
63+
64+
function s(strings, parameters) {
65+
return Core__Array.reduceWithIndex(parameters, strings[0], (function (acc, param, i) {
66+
var s = strings[i + 1 | 0];
67+
var p;
68+
switch (param.TAG) {
69+
case "I" :
70+
case "F" :
71+
p = param._0.toString();
72+
break;
73+
case "S" :
74+
p = param._0;
75+
break;
76+
case "Bool" :
77+
p = param._0 ? "true" : "false";
78+
break;
79+
80+
}
81+
return acc + p + s;
82+
}));
83+
}
84+
```
85+
86+
</CodeTab>
87+
88+
## Write tagged template literals
89+
90+
Now that you have defined your tag function, you can use it this way:
91+
92+
<CodeTab labels={["ReScript", "JS Output"]}>
93+
94+
```res example
95+
module Greetings = {
96+
@react.component
97+
let make = (~name, ~age) => {
98+
<div> {s`hello ${S(name)} you're ${I(age)} year old!`} </div>
99+
}
100+
}
101+
```
102+
```js
103+
function Greetings(props) {
104+
return React.createElement("div", undefined, s([
105+
"hello ",
106+
" you're ",
107+
" year old!"
108+
], [
109+
{
110+
TAG: "S",
111+
_0: props.name
112+
},
113+
{
114+
TAG: "I",
115+
_0: props.age
116+
}
117+
]));
118+
}
119+
```
120+
121+
</CodeTab>
122+
123+
Pretty neat, isn't it? As you can see, it looks like any regular template literal but it accepts placeholders that are not strings
124+
and it outputs something that is not a string either, a `React.element` in this case.

0 commit comments

Comments
 (0)