Tagged Template Literals
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints indicate eslint and semgrep can catch code patterns like unsanitised template interpolation or missing tagged templates for SQL queries, but these require rule configuration and are not caught by default linters on all misuses—only on specific anti-patterns.
Closest to 'simple parameterised fix' (e3). The quick_fix describes switching to a tagged template library (like htm), which is a localised refactor within a component: replace template literal syntax with a tag function call and ensure the tag function handles escaping. This doesn't span multiple files or require architectural change.
Closest to 'localised tax' (b3). Tagged templates are a pattern choice that applies to contexts where HTML/SQL interpolation occurs (web, cli per applies_to), but the burden falls on the component where the tag is used and developers who maintain that interpolation. It doesn't reshape the entire codebase or impose a system-wide architectural load—other components can use plain functions or other patterns.
Closest to 'serious trap' (t7). The misconception field explicitly states that developers often believe tagged templates are 'just syntax sugar' when they actually transform output entirely and receive raw values separately from strings. This contradicts superficial understanding and is further compounded by common_mistakes like forgetting the strings array has one more element than values, and the non-obvious requirement to manually sanitise values in the tag function—developers may assume the tag magic handles escaping automatically.
Also Known As
TL;DR
Explanation
A tagged template calls a function with the literal string parts (as an array) and the interpolated values as separate arguments. The tag function can process, escape, or transform both. Common uses: SQL query builders (prevent injection by separating literals from values), HTML escaping, CSS-in-JS, GraphQL queries (gql tag), and i18n formatting. The template tag is called at parse time if the values are all known — otherwise at runtime with the actual values.
Common Misconception
Why It Matters
Common Mistakes
- Not escaping HTML values in a custom html tag — the benefit is lost if values aren't sanitised.
- Forgetting that the strings array has one more element than the values array.
- Using tagged templates where a plain function would be clearer — tags are best for DSLs.
- Not handling the raw strings array for regex/string-escape use cases.
Code Examples
// SQL injection risk — string concatenation:
const query = `SELECT * FROM users WHERE id = ${userId}`;
// userId = '1 OR 1=1 --' → returns all users
// XSS risk — unescaped interpolation:
const html = `<div>${userInput}</div>`;
// Safe SQL via tagged template:
function sql(strings, ...values) {
return {
text: strings.reduce((q, s, i) => q + s + (i < values.length ? `$${i+1}` : ''), ''),
values, // Driver handles parameterised query
};
}
const query = sql`SELECT * FROM users WHERE id = ${userId}`;
// query = { text: 'SELECT * FROM users WHERE id = $1', values: [userId] }
// Safe HTML escaping:
const escape = s => String(s).replace(/&/g,'&').replace(/</g,'<');
const html = (strings, ...vals) => strings.reduce((r,s,i) => r+s+(vals[i]!=null?escape(vals[i]):''),'');
const output = html`<div>${userInput}</div>`;