Tagged templates

Since 11.1

Tagged templates provide a special form of string interpolation, enabling the creation of template literals where placeholders aren't restricted to strings. Moreover, the resulting output isn't confined solely to strings either. You can take a look at the JS documentation about tagged templates to learn more about them.

Define a tag function

Tagged template values in ReScript have the following type:

RES
let myTagFunction: taggedTemplate<'param, 'output>

The type parameters describe the interpolated values and the output. Use TaggedTemplate.make to lift a ReScript function that takes the string segments and an array of interpolated values into a tagged template value.

Given how string interpolation works, you'll always have the following invariant:

RES
Array.length(strings) == Array.length(placeholder) + 1

Let's say you want to interpolate strings with all kind of builtin types and make it work inside React components, you can define the following tag function:

ReScriptJS Output
type params =
  | I(int)
  | F(float)
  | S(string)
  | Bool(bool)

let s = TaggedTemplate.make((strings, parameters) => {
  let text = Array.reduceWithIndex(parameters, Array.getUnsafe(strings, 0), (
    acc,
    param,
    i,
  ) => {
    let s = Array.getUnsafe(strings, i + 1)
    let p = switch param {
    | I(i) => Int.toString(i)
    | F(f) => Float.toString(f)
    | S(s) => s
    | Bool(true) => "true"
    | Bool(false) => "false"
    }
    acc ++ p ++ s
  })
  React.string(text)
})

Write tagged template literals

Now that you have defined your tag function, you can use it this way:

ReScriptJS OutputJSX Preserved Output
module Greetings = {
  @react.component
  let make = (~name, ~age) => {
    <div> {s`hello ${S(name)} you're ${I(age)} year old!`} </div>
  }
}

Pretty neat, isn't it? As you can see, it looks like any regular template literal but it accepts placeholders that are not strings and it outputs something that is not a string either, a React.element in this case.