TypeScript - 템플릿 리터럴 타입

안녕하세요, 미래의 코딩 슈퍼스타 여러분! 오늘 우리는 TypeScript의 세계로 여행을 떠나고, 매력적인 기능인 템플릿 리터럴 타입을 탐구해볼 거예요. 프로그래밍에 새로운 사람이라면 걱정하지 마세요 - 저는 여러분을 단계별로 안내해드릴게요. 수년간 수많은 학생들을 가르쳐온 경험을 바탕으로 말이죠. 그럼 여러분의 좋아하는 음료를 손에 들고 편안하게 앉아, 시작해보겠습니다!

TypeScript - Template Literal Types

템플릿 리터럴 타입이란?

정밀한 부분으로 들어가기 전에, 템플릿 리터럴 타입이 무엇인지 이해해봅시다. 상상해보세요. 여러분이 인사 카드를 만들고 있는 중입니다. 기본 템플릿이 있지만, 다른 이름과 메시지로 개인화하고 싶어요. 이것이 TypeScript에서 템플릿 리터럴 타입이 하는 일입니다 - 우리는 변할 수 있는 입력에 따라 유연하고 재사용 가능한 타입 정의를 만들 수 있습니다.

문법

템플릿 리터럴 타입의 문법은처음에는 조금 이상하게 보일 수 있지만, 저 promise해드리겠습니다. 복잡하지 않습니다. 여기 기본 구조를 보여드릴게요:

type TemplateLiteralType = `prefix ${SomeType} suffix`;

이를 분해해보겠습니다:

  • type은 TypeScript에서 새로운 타입을 정의하는 데 사용되는 키워드입니다.
  • TemplateLiteralType은 우리가 새로운 타입에 부여한 이름입니다 (원하는 이름을 선택할 수 있습니다).
  • 백틱(`)은 템플릿을 감싸는 데 사용됩니다.
  • ${SomeType}은 우리가 다른 타입을 삽입할 수 있는 플레이스홀더입니다.
  • prefixsuffix는 선택 사항으로, 우리 타입의 일부로 항상 포함됩니다.

Mad Libs 게임을 떠올려보세요. ${SomeType}은 우리가 다양한 변형을 만들기 위해 채울 빈칸입니다.

예제

이제 템플릿 리터럴 타입이 실제로 어떻게 작동하는지 예제를 통해 살펴보겠습니다. 충분한 코드 샘플을 제공하고, 각각을 상세히 설명해드릴게요.

예제 1: 기본 사용

type Greeting = `Hello, ${string}!`;

let myGreeting: Greeting = "Hello, World!";  // 이는 유효합니다
let invalidGreeting: Greeting = "Hi there!"; // 이는 오류를 발생시킵니다

이 예제에서, 우리는 항상 "Hello, "로 시작하고 "!"로 끝나는 Greeting 타입을 만들었습니다. ${string} 부분은 우리가 중간에 어떤 문자열을 넣을 수 있음을 의미합니다. 인사 카드 템플릿에서 이름을 바꿀 수 있는 것과 같습니다.

예제 2: 문자열 리터럴 결합

type Color = "red" | "blue" | "green";
type Size = "small" | "medium" | "large";

type TShirt = `${Size}-${Color}`;

let myShirt: TShirt = "medium-blue";  // 이는 유효합니다
let invalidShirt: TShirt = "tiny-yellow";  // 이는 오류를 발생시킵니다

여기서 우리는 SizeColor 두 가지 타입을 결합하여 TShirt 타입을 만들고 있습니다. 이를 통해 "small-red"나 "large-green"과 같은 유효한 조합을 만들 수 있지만, "tiny-yellow"와 같은 무效한 조합을 방지할 수 있습니다.

예제 3: 숫자 사용

type Coordinate = `${number},${number}`;

let point: Coordinate = "10,20";  // 이는 유효합니다
let invalidPoint: Coordinate = "10,20,30";  // 이는 오류를 발생시킵니다

이 예제에서 우리는 number 대신 string을 사용하고 있습니다. 이는 2D 좌표를 나타내는 타입을 만듭니다. 쉼표로 구분된 두 개의 숫자여야 합니다.

예제 4: 복잡한 템플릿

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiEndpoint = `/${string}`;

type ApiRoute = `${HttpMethod} ${ApiEndpoint}`;

let validRoute: ApiRoute = "GET /users";
let anotherValidRoute: ApiRoute = "POST /update-profile";
let invalidRoute: ApiRoute = "PATCH /items";  // 이는 오류를 발생시킵니다

이 예제는 우리가 더 복잡한 타입을 만들 수 있음을 보여줍니다. 우리는 HTTP 메서드와 엔드포인트를 결합하여 ApiRoute 타입을 정의하고 있습니다. 이를 통해 우리의 API 라우트가 항상 특정 형식을 따르도록 보장할 수 있습니다.

예제 5: 대문자와 소문자 변환자

type Greeting = "hello" | "hi" | "hey";
type ShoutingGreeting = Uppercase<Greeting>;
type WhisperingGreeting = Lowercase<Greeting>;

let loud: ShoutingGreeting = "HELLO";  // 이는 유효합니다
let soft: WhisperingGreeting = "hi";   // 이는 유효합니다
let invalid: ShoutingGreeting = "Hey"; // 이는 오류를 발생시킵니다

TypeScript는 UppercaseLowercase와 같은 유틸리티 타입을 제공합니다. 이 예제는 우리가 기존 타입의 대문자나 소문자 버전을 만들 수 있음을 보여줍니다.

메서드 표

여기서 중요한 메서드와 유틸리티를 요약한 표를 제공해드리겠습니다:

메서드/유틸리티 설명 예제
기본 템플릿 고정된 전缀/후缀과 변수 부분을 가진 타입 생성 type Greeting = 'Hello, ${string}!'
연합 타입 여러 문자열 리터럴 타입을 결합 type Color = "red" \| "blue" \| "green"
대문자 변환 문자열 리터럴 타입을 대문자로 변환 type Upper = Uppercase<"hello">
소문자 변환 문자열 리터럴 타입을 소문자로 변환 type Lower = Lowercase<"HELLO">

결론

이제 여러분은 TypeScript의 템플릿 리터럴 타입의 놀라운 세계를 탐구했습니다. 기본 사용에서 복잡한 예제까지, 이 기능이 우리가 더 정밀하고 유연한 타입 정의를 만들 수 있도록 도와주는 것을 보셨습니다.

기억해 두세요, 새로운 기술을 배우는 것은 연습이 필요합니다. 즉시 이해가 되지 않으면 실망하지 마세요 - 수많은 학생들이 처음에는 어려워했지만 나중에는 "aha!"라는 순간을 겪었습니다. 계속 실험하고, 자신만의 타입을 만들어보세요. 그리고 가장 중요한 것은, 즐겁게 배우세요!

제 경험상, 배우는 과정을 즐기는 학생들이 가장 우수합니다. 따라서 TypeScript를 여러분의 코딩 도구箱에 있는 강력한 도구로 생각하고, 템플릿 리터럴 타입을 그 도구箱안의瑞士军刀로 생각하세요 - 다양하고 정확하며, 어떻게 사용하느냐에 따라 매우 유용합니다.

이제 새로운 지식으로 놀라운 것을 창조해 나가세요. 그리고 기억하세요, 프로그래밍의 세계에서 유일한 제한은 여러분의 상상력입니다 (그리고 가끔 컴파일러가 제한할 수 있지만, 그건 또 다른 이야기입니다).

즐거운 코딩 되세요!

Credits: Image by storyset