JS Template Literals on Steroids
Template Literals are what we used to call “Template Strings” used for string interpolation with embedded expressions. The features exists in other languages such as python and ruby for a long time and was first introduced to javascript in ECMAScript 6. Using template literals we can drop the ugly strings concatenations all together and use when we have embedded expressions and line breaks.
Basic Usage
The most common usage is to build a string composed of strings and values calculated from expressions. To embed an expression in a string all we need to do is to add the expression with curly brackets like${expression}
.
For example, to generate a localised date prepend with text we can write the following:
`Today is ${new Intl.DateTimeFormat('en-US').format(new Date())}`
Advanced Usage
There is more to the feature than strings and expressions combined together. We can build the end result by implementing a Tag Function which, given the strings and values of of the expression, compose the end result.
Tag functions is another tool allows to extract the logic of building strings to a function. Tag function can being used for HTML escaping, localisation, tagging, translations, etc. We use tag function by calling it before the template literal expression, for example fn`Today is ${new Date()}`
where fn is the tag function.
The Implementation
A tag function interface looks like:
function fn(strings, ...values): string
Where strings
is an array of the strings separated by the expressions and the values
are the expressions values. For example fn`Today is ${today} and Tomorrow is ${tomorrow}`
executes fn as fn(['Today is ', ' and Tomorrow is '], '6/23/2018', '6/24/2018')
.
The tag function implementation should always return a string considering strings
and values.
For example, to get a localised without localised it before we can implement a fmtDate
tag function:
function fmtDate(strings, date) {
const str0 = strings[0];
const str1 = strings[1];
const strDate = new Intl.DateTimeFormat('en-US').format(date);
return `${str0}${strDate}${str1}`;
}fmtDate`Today is ${new Date()}`; // “Today is 6/23/2018”
To take it one step further and localised all of the dates:
function fmtVar(v) {
return (v instanceof Date) ?
new Intl.DateTimeFormat('en-US').format(v) : v;
}function fmtString(strings, ...values) {
return values.reduce((acc, v, idx) =>
acc + fmtVar(v) + strings[idx + 1], strings[0]);
}fmtString`Today is ${today} and tomorrow is ${tomorrow}`;
// “Today is 6/23/2018 and tomorrow is 6/24/2018"
Notice that, in the example above, fmtStrings
is a general formatting function that can be used to format anything using fmtVar
which format a parameter by its type. We can use this combination to format any variables as we want.
Existing Raw Data Implementation
The common usages of tag functions is getting the raw data out of template string. For example first ${'\n'} second
to actually result with “first \n second” without breaking a line. We can use the String.raw
static method which does exactly this.
String.raw`first ${'\n'} second`; // "first \n second"
To Conclude
Template literal can be a shotgun when handling strings, not only for expressions but also to compose more complexed string. Translations, localisations and more can be a good usage for this tool. It can even be used as a templating engine, I know Polymer is using it when creating a component template inline in the component class providing a html`<template>`
function.
On the other hand, template literal should be used very carefully. The tag function usage and implementation is not that straight forward and can get unpredictable and hard to understand. Use it as another tool in the toolkit.