Template literals and tagged template literals
In JavaScript, literals represent values that you provided literally in code, not through variables.
The word "template" in English means "a thing that is used as a model for producing other similar examples".refs:templateDict
Template literal allows you to easily express a model for producing strings that look similar. This is possible because template literals can be made up of static texts with dynmaic parts in between.
Tagged template literal allows you to tag a template literal to the end of a function name. What happens then is that the function gets called with the template literal's static and dynamic parts giving you enormous power to produce any values you need by returning it from the function.
In this note I will go over all the theoretical stuffs about them that you need to know. Let's start exploring.
Template literal
The template literal (also known as an untagged template literal) is somewhat like a string literal. It is written within backticks (`
). Its value is always a string. It has two features:
- String interpolation
- Multiline strings
Let's see them in detail.
String interpolation
This is what makes template literals template.
You can place any expression within ${}
. This is called a placeholder.
The given expression within it is called a substitution. A placeholder must contain a substitution.
Text pieces separated 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 its individual parts in respective order to return a string value. This idea is called string interpolation. Below is an example:
console.log(`JavaScript is ${new Date().getFullYear() - 1995} years old.`);
// JavaScript is 29 years old.
Figure 1 shows the names of the parts of above template literal.
Let's see another interesting example:
console.log(`Let's put an array: ${[1, `${[2.1, 2.2]}`, 3]}!`);
// Let's put an array: 1,2.1,2.2,3!
Note that, the feature that substitution can be any JavaScript expression allows you to compose nested template literals!
Multiline strings
Now you can write a multiline string just by creating real newlines in code like below:
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 literal
Tagged template literal is also called tagged template for short.refs:exploringjs It is made up of a template literal tagged onto a function name or more precisely a function expression like below:
funcitonExpression`template literal`;
Here the function expression is called the tag function.
JavaScript calls the tag function by passing it parts of the template literal next to it. The return value of this function is the value of the tagged template. This value can be anything.
JavaScript provides arguments to the tag function like below:
-
1st argument: This is an array holding the cooked interpretationnotes:cooked 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 raw interpretationnotes:raw of the template strings. - Unicode codepoint escapes (eg.
-
Remaining arguments: These are the evaluated values of the substitutions. Note that these are not converted to strings from other types of values.
That's all the theoretical stuff you need to know to be confident in using it. Do the exercises below to make sure you understand it really well.
Exercises
What will the output of the following codes?
'\unicode is awesome'
`\unicode is awesome`
'\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`;
((...args) => args[0].raw[0])`\unicode is awesome`;
"\\unicode is awesome";
How is it possible?
["one", "two", "three"].join` -> `.concat` ---> 💥`;
// 'one -> two -> three ---> 💥'
["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.
Note that if you use placeholders in the template literal, the result will probably not be as expected:
"Hello ".concat`Jimmy, ${"Peter"} and ${"John"}! Welcome`;
// 'Hello Jimmy, , and ,! WelcomePeterJohn'
Except doing code golfrefs:codegolf I don't recommened using join
and concat
like this.
If there are $n$ substitutions, what is the length of the array that we get as the first argument of tag function?
$$ 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!
Implement highlight
that works like below:
highlight`${1}`;
// '👉1👈'
highlight`This is ${"cool"}.`;
// 'This is 👉cool👈.'
highlight`${1}`;
// '👉1👈'
highlight`This is ${"cool"}.`;
// 'This is 👉cool👈.'
The reduce
method makes it really easy to do:
const highlight = (strs, ...values) =>
strs.reduce((result, str, i) => `${result}👉${values[i - 1]}👈${str}`);
console.log(highlight`${1}`);
console.log(highlight`This is ${"cool"}.`);
// '👉1👈'
// 'This is 👉cool👈.'
If you are new to the ...
dots syntax above or the reduce
method, I've written in-depth articles on them. I hope you will find them will helpful:
Conclusion
Congratulations! This article was dense with information. Now you know what template literal and tagged template literals are and how they works. Tagged template literals are not used as often as template literals but they have some interesting practical use cases worth knowing.
For digging more or to study practical usages of tagged template literals, here are some good resources:
Notes
- [cooked] Cooked interpretation means the backslashes have special meaning. For example
\n
will produce a single character which is a newline character. - [raw] Raw interpretation means backslashes don't have special meaning. So
\n
will produce two characters:\
andn
.
References
- [templateDict] Meaning of "template" from Oxford Learner's Dictionary
- [codegolf] Code golf
- [exploringjs] Exploring ES6 by Dr. Axel Rauschmayer