Lesson 42 of 80
Put a function name in front of a template string and you get the literal pieces and the interpolated values handed to you separately — the trick behind styled-components and safe HTML escaping.
15 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A normal template literal builds a string immediately: `Hello ${name}` interpolates and you get back one finished string. A tagged template literal — tag`Hello ${name}` — doesn't build the string at all. Instead it calls tag as a function and hands it two things separately: an array of the literal text chunks, and the interpolated values, unjoined.
function tag(strings, ...values) {
console.log(strings); // ["Hello ", "!"]
console.log(values); // ["Ada"]
}
tag`Hello ${"Ada"}!`;
strings is ["Hello ", "!"] — the static parts, split wherever an interpolation occurred. values is ["Ada"] — the interpolated parts, in order. The tag function decides what to do with them and returns whatever it wants: a string, an object, anything.
The most concrete reason this exists: you can force every interpolated value through a safety function before it ever reaches the final string, and there's no way for a caller to bypass it.
function safeHTML(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i - 1];
const escaped = typeof value === "string"
? value.replace(/</g, "<").replace(/>/g, ">")
: value;
return result + escaped + str;
});
}
const userInput = "<script>alert('hi')</script>";
const html = safeHTML`<p>Comment: ${userInput}</p>`;
// "<p>Comment: <script>alert('hi')</script></p>"
Every interpolated value passes through the escaping logic automatically — a developer can't accidentally write an unescaped interpolation because the tag function is the only thing that ever sees the raw pieces and does the joining.
This is exactly the mechanism styled-components uses. styled.div`color: ${props => props.color};` isn't string concatenation with extra steps — styled.div is a tag function that receives the CSS text chunks and a function value separately, and builds a component that re-evaluates the interpolated function against each render's props.
Promise, a DOM node, anything.strings always has one more element than values. For n interpolations there are n+1 literal chunks (the parts before, between, and after each ${}), which is why the escaping example above zips them with values[i - 1].strings object each time, which is why library code can safely use strings itself as a cache key.Tagged templates are what plain template literals look like once you accept a function argument before evaluating the interpolations — the same ${} syntax you already know, just intercepted before it becomes a string instead of after. Anywhere this platform's code touches a DSL embedded in a string (styled-components' CSS-in-JS, GraphQL's gql tag, SQL query builders), this is the feature making it possible.