Template literals and tagged template literals

Template literals are a handy way to include any values inside of a string. With template literal you always get a string value. Tagged template literals give you complete freedom over the return value of a template literal and gives you access to the parts of it through a function called the tag function.

Table of contents

Here we will take an in-depth look at both of them. But I will not include the practical usages and examples of tagged template literals so that we can focus on how it works very well without becoming overwhelmed. After going through this article you will have all the required knowledge of it to study any of it's practical examples.

Let's start exploring.

Bird eye view

First let's take a bird eye view of both of them.

Template literals(aka untagged template literals)

let n = 9;
let squareStr = `The square of ${n} is ${ n * n }.`; 
console.log(squareStr);
// The square of 9 is 81.

let poem = 
`
from my bed
I watch
3 birds
on a telephone
wire.
  -- Charles Bukowski 
`;
console.log(poem)
// output
/*
from my bed
I watch
3 birds
on a telephone
wire.
  -- Charles Bukowski 
*/

Tagged template literals(aka tagged templates)

With tagged templates we can get access to the individual parts of a template literal and return any value we wish!

For this we need a function to tag to the template literal:

function highlightInsertedParts(templateStrings, ...substitutions) {
  // console log to see what's in templateStrings and substitutions

  let result = templateStrings[0];
  for (let i = 1; i < templateStrings.length; i++) {
    result += `👉${substitutions[i - 1]}👈${templateStrings[i]}`;
  }
  return result;
}
Info: If the ...substitution is syntax is new to you, here is your short guide: It says pack the rest of the arguments given to the function highlightInsertedParts into an array called substitution.

Now we can tag this function to a template literal to create tagged template literal:

highlightInsertedParts`${1}`; 
// '👉1👈'

highlightInsertedParts`This is ${'cool'}.`  
// 'This is 👉cool👈.'

If this you don't understand it fully, don't worry. This example will make full sense, once you go through this article.

Deep dive

Template literal

Template literal diagram

Template literal(aka untagged template literal) is somewhat like a string literal. It's written within backticks(`). It's value is always a string. It gives the following unique advantages that string literals don't give us:

Firstly, string interpolation. We can place any expression in it within ${ } which is called a placeholder. The given expression within it is called a substitution. A placeholder must contain a substitution. The each chunk of text seperated by placeholders are called template strings. JavaScript evaluates the substitutions and in this process converts them to strings if they are not and joins all of it's individual parts in respective order to return a string value. For example:

`Let's put an array: ${[1, `${ [2.1, 2.2] }`, 3]}!`
// it will return:
"Let's put an array: 1,2.1,2.2,3!"

Note that, the feature that substitution can be any JavaScript expression allows to compose nested template literals!

Secondly, multiline strings. Now we can write multiline string just by creating real newline in code:

`
A line
A new line
`

Note that if you want to get backtick or a placeholder in the output of template literals literally, we need to escape them with backslash(\):

`\`This is a \${'template'} literal too\``
// output
"`This is a ${'template'} literal too`"

Tagged template literal

Tagged template literal is also called tagged template for short.1 It's syntax is like below:

expression`template literal`

Tagged template has two parts:

  1. expression: This is an expression which must evaluate to a function. This function is called tag function.
  2. `template literal`: It can be any template literal. The only difference is that we don't get any joined string value like before.

A tag function gets the access to it's template literals each part through it's arguments. The return value of this function is the value of the tagged template.

Cooked and raw interpretation of template strings

To understand the tag function properly we need to understand two more things: the cooked and raw interpretation of template strings, because tag function gives us access to both forms.

  • Cooked interpretation means the backslashes have special meaning. For example \n will produce a single character which is a newline character.
  • Raw interpretation means backslashes don't have special meaning. So \n will produce two characters: \ and n.

Tag function

Finally we have reached to the heart of tagged template, the tag function. JavaScript gives us access to the parts of it's template literal thorough it's arguments like below:

  • 1st argument: This is an array holding the cooked interpretation of template strings. However if a template string holds incorrect syntax of the following kind of escape sequences then the corresponding array element of that template string will hold undefined.

    • Unicode codepoint escapes (eg. \u{1F642})
    • Unicode unit escapes (eg. \u03A3)
    • Hexadecimal escapes (eg. \x41)

    This array has a raw named property which holds all the raw interpretation of the template strings.

    Info: If untagged template literal or string literal holds incorrect syntax of the above escape sequences, JavaScript will throw error.

  • Remaining arguments: These are the substitutions.

The return value of tag function is the value of the tagged template. This value can be anything.

That's it. Now you know all the theories 😎 Do the quizzes to make sure you know it really well.

Quizzes

Run code in brain

What will the output of the following codes?

'\unicode is awesome'
`\unicode is awesome`

JavaScript will throw error because invalid unicode escape sequences are not allowed in string and template literals.

What will be the output of the following line?

((...args) => args[0].raw[0])`\unicode is awesome`
'\\unicode is awesome'

How is it possible?

["one", "two", "three"].join` -> `.concat` ---> 💥`
// 'one -> two -> three ---> 💥'

join and concat are not built as tag functions but here they are treated as tag functions.

They both get as their first argument, an array containing a single string. These functions then convert these arrays to strings to continue their job and we get the above output.

Sometimes programmers get crazy and use this trick for saving a few bytes. Be careful that if you use placeholders in the template literal, the result will probably not be as expected. For example:

'Hello '.concat`Jimmy, ${'Peter'} and ${'John'}! Welcome`
// 'Hello Jimmy, , and ,! WelcomePeterJohn'

What is the length of 1st argument of tag function(which is an array)?

If there are n substitutions, what is the length of the array that we get as the first argument of tag function?

Answer: n + 1

This is always true. For example:

tagFunc`${'one'} and two and ${'three'}`

In this case the array will be ['', ' and two and ', '']. If we didn't get that empty strings, it would be impossible for the tagFunc to decide the order of the parts of the template literal. Say thanks to these useful empty strings!

Further study

For digging more or to study practical usages, here are some good resources:

References

If you found this article helpful, please buy me a coffee