JavaScript - Template Literals와 Tagged Templates

2025년 01월 07일

JavaScript의 Template Literals는 단순한 문자열 포매팅 이상의 기능을 제공합니다. Template Literals의 동작 원리부터 Tagged Templates를 활용한 실제 라이브러리 사례까지 살펴보겠습니다.

Template Literals의 동작 원리

처음 Template Literals를 배우면 단순히 문자열을 편하게 작성하는 방법으로만 알 수 있습니다.

const name = "JavaScript";
const greeting = `Hello ${name}!`;
console.log(greeting); // "Hello JavaScript!"

하지만 Template Literals는 내부적으로 더 복잡한 동작을 수행합니다. 이해를 돕기 위해 간단한 함수를 만들어 보겠습니다.

function examineTemplate(strings, ...values) {
  console.log("정적 부분:", strings);
  console.log("동적 값:", values);

  // 기본 Template Literal처럼 동작하도록 구현
  let result = strings[0];
  for (let i = 0; i < values.length; i++) {
    result += values[i] + strings[i + 1];
  }
  return result;
}

const name = "JavaScript";
const version = 22;
const result = examineTemplate`언어: ${name}, 버전: ${version}`;

// 정적 부분: ['언어: ', ', 버전: ', '']
// 동적 값: ['JavaScript', 22]

console.log(result);
//언어: JavaScript, 버전: 22

이 예시를 통해 우리는 Template Literals가 단순한 문자열 치환이 아니라, 문자열을 정적 부분 / 동적 값으로 분리하여 처리한다는 것을 알 수 있습니다.

Tagged Templates로 확장하기

Template Literals의 이러한 특성을 활용하여, Tagged Templates를 통해 문자열 처리 방식을 커스터마이즈할 수 있습니다.

function upperCase(strings, ...values) {
  return strings.reduce(
    (result, str, i) =>
      result + (values[i] ? values[i].toString().toUpperCase() : "") + str
  );
}

const name = "javascript";
console.log(upperCase`Hello ${name}!`); // "Hello JAVASCRIPT!"

Tagged Templates 활용 예시

Tagged Templates를 활용한 몇 가지 예시를 살펴보겠습니다.

SQL 쿼리 빌더

function sql(strings, ...values) {
  return strings.reduce((query, string, i) => {
    if (i < values.length) {
      // SQL 인젝션 방지를 위한 이스케이프 처리
      return query + string + escapeSQL(values[i]);
    }
    return query + string;
  }, "");
}

const userId = "user'; DROP TABLE users; --";
const query = sql`SELECT * FROM users WHERE id = ${userId}`;
// 결과: "SELECT * FROM users WHERE id = 'user''; DROP TABLE users; --'"

실제 라이브러리에서의 활용

Tagged Templates 개념은 실제 많은 라이브러리들에게 사용되고 있습니다. 기존에 많이 사용했던 gql, styled-component의 문법 역시 Tagged Templates를 활용했습니다.

1. GraphQL (graphql-tag)

*실제 graphql-tag 라이브러리는 더 복잡한 파싱과 검증을 수행합니다:

import gql from 'graphql-tag';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      name
      email
      posts {
        title
      }
    }
  }
`;

2 Styled Components

import styled from 'styled-components';

const Button = styled.button`
  background-color: ${props => props.primary ? 'blue' : 'white'};
  color: ${props => props.primary ? 'white' : 'black'};
  padding: 10px 20px;
  border: 2px solid blue;
  border-radius: 4px;
  
  &:hover {
    opacity: 0.8;
  }
`;

마무리

Template Literals와 Tagged Templates는 단순한 문자열 포매팅을 넘어서는 강력한 기능을 제공합니다. 정적 부분과 동적 값을 분리하여 처리하는 특성은 다양한 용도로 활용될 수 있으며, 실제로 많은 현대적인 JavaScript 라이브러리들이 이 기능을 활용하고 있습니다.

참고자료

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals#tagged_templates


TAGS
JAVASCRIPT