type Category = '한식' | '중식' | '일식' | '기타';
function printCategory(category: Category) {
// '한식', '중식', '일식', '기타' 중 하나
}
printCategory('한식'); // OK
printCategory('한...식'); // ERROR
위와 같이 문자열을 강제하는 String Literal Type을 사용하는 것은 자주 보셨을 겁니다.
타입스크립트의 기능 중 하나인 Template Literal Type을 사용하면 더 다양한 String Literal Type을 만들 수 있습니다.
기본적인 사용법
type HttpMethods = 'GET' | 'OPTION' | 'HEAD';
type HttpUrlPaths = '/animals' | '/fruits';
type HttpEndpoints = `${HttpMethods} ${HttpUrlPaths}`;
// 'GET /animals' | 'OPTION /animals' | 'HEAD /animals' | 'GET /fruits' | 'OPTION /fruits' | 'HEAD /fruits'
먼저, Back quote (`)를 사용하여 문자열을 나타냅니다. 그리고 ${}
를 사용하여 String Literal Type을 넣습니다. 템플릿에 삽입된 기존의 String Literal Type으로 새로운 String Literal Type이 만들어집니다.
예시: Union Type을 사용하여 만들기
type Events = 'click' | 'hover' | 'keyup' | 'keydown';
type EventHandlers = `on${Events}`;
// 'onclick' | 'onhover' | 'onkeyup' | 'onkeydown';
Events
라는 타입에서 on
이라는 단어를 붙여 'onclick' | 'onhover' | 'onkeyup' | 'onkeydown'
라는 새로운 Union Type을 만들 수 있습니다.
예시: Primitive Type을 사용하여 만들기
type HttpEndpoints =
| `GET /animals/popular`
| `GET /animals/${number}`
| `GET /animals/search/${string}`;
number
, string
타입을 넣을 수도 있습니다.
아쉽게도 number
, string
은 포괄적인 타입이므로 VSCode에서 자동완성으로 표시되지는 않습니다.
타입 자체는 의도한 대로 잘 작동하므로 참고하시면 될 것 같습니다.
참고로, boolean
은 true | false
로 잘 동작합니다.
예시: Conditional Type에서 사용하기
function $<T extends `${string}?` | `${string}`>(
selector: T
): typeof selector extends `${string}` ? Element | null : Element {
const $element = document.querySelector(selector.endsWith('?') ? selector.slice(0, -1) : selector);
if ($element === null) {
throw new Error('Element not found!');
}
return $element;
}
const $ul = $('ul'); // Element
const $nullableUl = $('ul?'); // Element | null
extends
를 사용한 Conditional Type에서도 사용할 수 있습니다.
위의 예시에서는 인자로 주어진 selector 라는 문자열이 맨 끝에 ?가 붙어있는지 검사합니다. 이에 따라 리턴 타입이 결정됩니다.
예시: infer를 사용하여 String Literal Type 추출하기
type HttpEndpoints =
| `GET /animals/popular`
| `GET /animals/${number}`
| `GET /animals/search/${string}`
| `POST /animals`
| `POST /animals/${number}`
| `PUT /animals/${number}`;
type GetHttpMethods<T> = T extends `${infer U} ${string}` ? U : never;
type HttpMethods = GetHttpMethods<HttpEndpoints>;
// 'GET' | 'POST' | 'PUT'
기존의 String Literal Type에서 원하는 부분만 추출하여 사용할 수도 있습니다. Conditional Type과 함께 infer
키워드를 쓰면 해당 부분만 추출하는 타입을 만들 수 있습니다.
라이브러리
이러한 타입의 문법들을 응용하여 다양한 편리 기능들을 제공하는 라이브러리들이 많습니다.
- tani/jsonup: String Literal Type으로 된 JSON을 파싱한 타입으로 만들어 줍니다.
- g-plane/typed-query-selector:
querySelector
를 분석하여 적합한 반환HTMLElement
타입을 만들어 줍니다.
빌트 인(Built-in) 타입 유틸리티
타입스크립트에 내장되어 있는 유틸리티 타입들입니다. 간단한 것들이기 때문에 설명 없이 입출력만 첨부하였습니다.
Uppercase<StringType>
Lowercase<StringType>
Capitalize<StringType>
Uncapitalize<StringType>
맺음말
기존에는 String Literal Type을 일일이 하드코딩하여 타입을 정의해주어야 했습니다. 하지만 Template Literal Type을 사용하면 더 강력한 타입들을 만들 수 있을 겁니다! 특히 Conditional Type과 잘 연계해서 쓴다면 정말 멋진 타입을 만들어 나갈 수 있지 않을까 싶습니다.