Tagged Template Literals
Tagged Template Literal — вызов функции-тега перед шаблонной строкой, где тег получает массив статичных частей и вычисленные выражения, позволяя полностью контролировать сборку результата.
Зачем нужно
Tagged templates дают возможность обрабатывать шаблонные строки как DSL: экранировать HTML, форматировать SQL, переводить строки, стилизовать компоненты. Это позволяет строить безопасные и выразительные API прямо в JavaScript-синтаксисе.
Где используется
- Экранирование HTML (защита от XSS)
- Параметризованные SQL-запросы (защита от SQL injection)
- CSS-in-JS (styled-components используют tagged templates)
- Интернационализация и форматирование строк
- GraphQL-запросы (библиотека
gql)
Основной контент
Базовый синтаксис
// Тег — функция, принимающая (strings, ...values())
function tag(strings, ...values()) {
console.log(strings); // массив строковых частей (raw)
console.log(values); // массив вычисленных выражений
return 'результат'; // тег может вернуть что угодно
}
const name = 'Мир';
const count = 42;
tag`Привет, ${name}! Ответ: ${count}.`;
// strings: ['Привет, ', '! Ответ: ', '.']
// values: ['Мир', 42]
Пример: HTML-экранирование
function html(strings, ...values()) {
const escape = (v) => String(v)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
return strings.reduce((result, str, i) => {
const value = values[i - 1];
return result + escape(value) + str;
});
}
const userInput = '<script>alert("XSS")</script>';
const safeHtml = html`<p>Пользователь написал: ${userInput}</p>`;
console.log(safeHtml);
// <p>Пользователь написал: <script>alert("XSS")</script></p>
Пример: SQL параметризация
function sql(strings, ...values()) {
const query = strings.reduce((q, str, i) => {
return q + (i > 0 ? `$${i}` : '') + str;
});
return { query, params: values };
}
const userId = 42;
const status = 'active';
const { query, params } = sql`
SELECT * FROM users
WHERE id = ${userId} AND status = ${status}
`;
// query: 'SELECT * FROM users WHERE id = $1 AND status = $2'
// params: [42, 'active']
// Безопасно от SQL injection!
Styled-components стиль
// Упрощённая имитация styled-components
function styled(tag) {
return (strings, ...values()) => {
const css = strings.reduce((result, str, i) => {
const value = typeof values[i] === 'function'
? values[i]({ theme: 'light' }) // props/theme injection
: (values[i] ?? '');
return result + str + value;
}, '');
const className = `sc-${Math.random.toString(36).slice(2, 8)}`;
const style = document.createElement('style');
style.textContent = `.${className} { ${css} }`;
document.head.appendChild(style);
return `${tag}.${className}`;
};
}
const Button = styled('button')`
background: ${props => props.primary ? 'blue' : 'white'};
padding: 8px 16px;
border-radius: 4px;
`;
strings.raw — необработанные строки
// String.raw — встроенный тег, возвращает строку без обработки escape
const path = String.raw`C:\Users\name\Documents`;
console.log(path); // 'C:\Users\name\Documents' (не \U, \n, \D)
// strings.raw в кастомном теге
function debug(strings, ...values()) {
return strings.raw.reduce((result, str, i) => {
return result + (values[i - 1] ?? '') + str;
});
}
const n = 10;
console.log(debug`Значение: ${n}\nСледующая строка`);
// 'Значение: 10\nСледующая строка' (литеральный \n, не перенос)
Частые ошибки
strings.length === values.length + 1— строковых частей всегда на одну больше чем значений. Не забывайте обрабатывать первую часть (strings[0]) и последнюю (strings[strings.length - 1]).- Возврат не строки из тега — тег может вернуть любой тип: массив, объект, null. TypeScript и другие инструменты могут этого не ожидать.
- Пропуск
strings.rawпри работе с путями — обычныйstrings[i]обрабатывает escape-последовательности (\n→ перенос строки). Для путей используйтеstrings.raw[i].
Связанные темы
Ресурсы
⚡ Источник: JavaScript template literal или 100 плюс 1 способ вызвать функцию · AsForJS
- 📅 2023-05-29 · YouTube
- Тезисы:
- Tagged template — это форма function call:
fn\hello ${x}`≡fn(['hello ', ''], x)` - Это альтернативная грамматика вызова — без скобок, с особыми аргументами
strings.rawхранит исходный текст без обработки escape (для регексов, путей, latex)- Используется в styled-components, GraphQL tag, lit-html, sql tagged templates
- Tagged template — это форма function call:
🎓 Источник: Work with strings, templates and Unicode
- 📅 2018-10-18 · YouTube
- Тезисы: template literals — это синтаксический сахар с двумя режимами: untagged (просто интерполяция) и tagged (полный контроль). Это базис для построения eDSL в JS