Explain the concept of tagged templates
TL;DR
Tagged templates in JavaScript allow you to parse template literals with a function. The function receives the literal strings and the values as arguments, enabling custom processing of the template. For example:
function tag(strings, ...values) {return strings[0] + values[0] + strings[1] + values[1] + strings[2];}const result = tag`Hello ${'world'}! How are ${'you'}?`;console.log(result); // "Hello world! How are you?"
Tagged templates
What are tagged templates?
Tagged templates are a feature in JavaScript that allows you to call a function (the "tag") with a template literal. The tag function can then process the template literal's parts (both the literal strings and the interpolated values) in a custom way.
Syntax
The syntax for tagged templates involves placing a function name before a template literal:
function tag(strings, ...values) {// Custom processing}tag`template literal with ${values}`;
How it works
When a tagged template is invoked, the tag function receives:
- An array of literal strings (the parts of the template that are not interpolated)
- The interpolated values as additional arguments
For example:
function tag(strings, ...values) {console.log(strings); // ["Hello ", "! How are ", "?"]console.log(values); // ["world", "you"]}tag`Hello ${'world'}! How are ${'you'}?`;
Use cases
Tagged templates can be used for various purposes, such as:
- Context-aware escaping: Encoding interpolated values for one specifically defined output context
- Localization: Translating template literals into different languages
- Custom formatting: Applying custom formatting to the interpolated values
Example
Here is a simple example of a tagged template that escapes interpolated values for an HTML text-content context:
function escapeHTMLText(strings, ...values) {return strings.reduce((result, string, i) => {const escapedValue =i < values.length? String(values[i]).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'): '';return result + string + escapedValue;}, '');}const userInput = '<script>alert("XSS")</script>';const result = escapeHTMLText`User input: ${userInput}`;console.log(result); // "User input: <script>alert("XSS")</script>"
This tag only defines encoding for HTML text content; it is not a general XSS sanitizer for attributes, URLs, CSS, or JavaScript contexts. When updating the DOM with plain text, assigning to textContent is simpler and safer. A production HTML-producing tag needs a well-reviewed, context-aware implementation.