
JavaScript의 템플릿 리터럴(` )을 타입 레벨에서 사용하는 기능입니다.
문자열 유니언 타입을 조합하거나, 특정 형식의 문자열만 허용하는 타입을 만들 때 유용합니다.
type Direction = "top" | "bottom" | "left" | "right";
type CSSProperty = `margin-${Direction}`;
// "margin-top" | "margin-bottom" | "margin-left" | "margin-right"
| 패턴 | 설명 |
|---|---|
`prefix-${T}` | T의 각 멤버 앞에 문자열을 붙인 타입 |
`${T}-suffix` | T의 각 멤버 뒤에 문자열을 붙인 타입 |
`${T}-${U}` | T × U의 모든 조합으로 이루어진 타입 |
Uppercase<T> / Lowercase<T> | 문자열 타입을 대·소문자로 변환 |
Capitalize<T> / Uncapitalize<T> | 첫 글자만 대·소문자로 변환 |
이벤트 시스템 설계하기
아래 Post 타입과 이벤트 이름 규칙을 기반으로, 4가지 상황에 맞는 타입을 템플릿 리터럴 타입으로 만들어보세요.
type Post = {
id: number;
title: string;
content: string;
authorId: number;
published: boolean;
createdAt: Date;
};
type Action = "create" | "update" | "delete" | "publish";
이벤트 이름 규칙은 on + 리소스명(대문자 시작) + 액션명(대문자 시작)입니다.
예: "onPostCreate", "onPostUpdate"
Action을 기반으로 "onPostCreate" | "onPostUpdate" | "onPostDelete" | "onPostPublish" 형태의 이벤트 이름 유니언 타입을 정의하십시오.
문제 풀어보기 =>
type PostEventName = ?
각 이벤트 이름을 키로, () => void 핸들러를 값으로 갖는 객체 타입을 정의하십시오.
문제 풀어보기 =>
// 예시
const handlers: PostEventHandlerMap = {
onPostCreate: () => console.log("created"),
onPostUpdate: () => console.log("updated"),
onPostDelete: () => console.log("deleted"),
onPostPublish: () => console.log("published"),
};
type PostEventHandlerMap = ?
Post의 각 키를 기반으로 getTitle, getContent 같은 형태의 getter 이름 유니언 타입을 정의하십시오.
문제 풀어보기 =>
type PostGetter = ?
// "getId" | "getTitle" | "getContent" | "getAuthorId" | "getPublished" | "getCreatedAt"
spacing 값(4 | 8 | 16)과 방향(top | bottom | left | right)을 조합한
"p-top-4", "m-bottom-8" 같은 형태의 CSS 유틸리티 클래스 타입을 정의하십시오.
문제 풀어보기 =>
type SpacingValue = 4 | 8 | 16;
type Side = "top" | "bottom" | "left" | "right";
type SpacingClass = ?
// "p-top-4" | "p-top-8" | ... | "m-bottom-16" | ...
type PostEventName = `onPost${Capitalize<Action>}`;
// 결과
type PostEventName =
| "onPostCreate"
| "onPostUpdate"
| "onPostDelete"
| "onPostPublish";
Capitalize로 "create" → "Create" 로 변환한 뒤 앞에 "onPost"를 붙입니다.
유니언 타입을 넣으면 각 멤버에 자동으로 적용되어 모든 조합이 만들어집니다.
type PostEventHandlerMap = {
[K in PostEventName]: () => void;
};
// 결과
type PostEventHandlerMap = {
onPostCreate: () => void;
onPostUpdate: () => void;
onPostDelete: () => void;
onPostPublish: () => void;
};
Mapped Type과 함께 쓰면 유니언 타입의 각 멤버를 키로 갖는 객체 타입을 만들 수 있습니다.
type PostGetter = `get${Capitalize<string & keyof Post>}`;
// 결과
type PostGetter =
| "getId"
| "getTitle"
| "getContent"
| "getAuthorId"
| "getPublished"
| "getCreatedAt";
keyof Post는 string | number | symbol 을 반환할 수 있으므로,
string & 로 교차해 문자열 키만 걸러낸 뒤 Capitalize를 적용합니다.
type SpacingClass = `${"p" | "m"}-${Side}-${SpacingValue}`;
// 결과 (일부)
type SpacingClass =
| "p-top-4"
| "p-top-8"
| "p-top-16"
| "p-bottom-4"
// ...
| "m-right-16";
세 개의 유니언(2 × 4 × 3)을 조합하면 TypeScript가 가능한 모든 경우의 수(24가지)를 자동으로 계산합니다.
Capitalize / Uppercase 등의 내장 문자열 유틸리티와 함께 쓰면 강력하다keyof와 함께 쓸 때는 string & 교차로 문자열 키만 필터링하는 것을 잊지 말자문자열 규칙이 있는 곳이라면 어디든 — 이벤트 이름, API 경로, CSS 클래스, i18n 키 —
템플릿 리터럴 타입으로 오타를 컴파일 타임에 잡을 수 있습니다.