IT일상

타입스크립트 템플릿 리터럴 타입

  • 프론트엔드
Profile picture

Written by solo5star

2023. 3. 27. 15:23

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 타입을 넣을 수도 있습니다.

1

아쉽게도 number, string은 포괄적인 타입이므로 VSCode에서 자동완성으로 표시되지는 않습니다.

2

타입 자체는 의도한 대로 잘 작동하므로 참고하시면 될 것 같습니다.

3

참고로, booleantrue | 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>

5

Lowercase<StringType>

6

Capitalize<StringType>

7

Uncapitalize<StringType>

8

맺음말

기존에는 String Literal Type을 일일이 하드코딩하여 타입을 정의해주어야 했습니다. 하지만 Template Literal Type을 사용하면 더 강력한 타입들을 만들 수 있을 겁니다! 특히 Conditional Type과 잘 연계해서 쓴다면 정말 멋진 타입을 만들어 나갈 수 있지 않을까 싶습니다.

참고자료


Profile picture

Written by solo5star

안녕하세요 👋 개발과 IT에 관심이 많은 solo5star입니다

  • GitHub
  • Baekjoon
  • solved.ac
  • about
© 2023, Built with Gatsby