Exploration of Tagged template Literals - Julien Cavaleiro

Exploration of Tagged template Literals

Tagged template literal is a powerful feature of JS, standardized with ES2015, and supported by most browser.

But, how does it work exactly?

It's a special function where you can add custom interpolation.

Interpolation example :

  • highlight text.
  • create custom CSS (see css-in-js solutions).
  • interpolate variables from SQL query (more below).

And here a custom tagged template function:

function myTaggedTemplate(parts, coolVariable) {
  console.log(parts);
  console.log(coolVariable);
}

myTaggedTemplate`Tagged template are ${"cool"}.`;
// => ["Tagged template are ", "."]
// => cool

Great, but how do I do custom interpolation? 😁

Well, ok. I'm going to provide a better example. But before that, a bit more why I ended up with tagged template.

I'm working on a company which build an ERP. We are trying to modernize the core of it and make the modernization of it as simple as possible for other employee.

In that research, we ended wanting to have a small wrapper around SQL because most employee who use our tools known SQL well but not JS.

Merge query with user input is not a good idea to avoid SQL injection.

This is why we end up with tagged template. Tagged template isolate user input by default. And this is a wonderful feature.

The other interesting part : SQL driver already sanitize input for SQL command. Since tagged template separate query from input, the work is done.

Here how it looks :

const { query, variables } = query`
  SELECT desc, unit, price
  from sales
  where status = ${"completed"} and customer_id = ${15735}
  order by created_at desc
`;
// query => select desc, unit, price from sales where status = :0 order by created_at desc
// variables => ["completed", 15735]

completed and 15735 are inline here but that data came from user input.

And how it works :

// we use `...variables` because we don't know how many `${}` developers are going to use.

function query(parts, ...variables) {
  let query = "";
  // we need to concatenate the string parts.
  for (let i = 0, size = parts.length; i < size; i++) {
    query += parts[i];
    // if we have a variables for it, we need to bind it.
    if (variables[i]) {
      query += ":" + i;
    }
  }

  return { query, variables };
}

The function split query from variables by default. And then, we can leverage on the SQL driver to make a safe query and avoid SQL injection.

The example right here is because I use oracle as a database at work. Other driver my expect something else then :0, :1, and so on.

Same example with execute from oracledb

const { query, variables } = query`
  SELECT desc, unit, price
  from sales
  where status = ${"completed"} and customer_id = ${15735}
  order by created_at desc
`;
// connection object from oracledb
const result = await connection.execute(query, variables);

Pretty cool, uh?


Here is a list of interesting concept with tagged templates :

  • zebu : a parser to build little language.
  • htm : build react components like without the need of babel.
  • styled components: CSS-in-JS library.