TypeScript 타입 유틸리티 완전 정복: 내장 도구부터 문자열 조작까지

TypeScript는 정적 타입 시스템을 통해 런타임 오류를 줄이고, 코드의 안정성과 유지보수성을 높이는 데 큰 역할을 한다. 특히 내장된 타입 유틸리티(Utility Types)는 기존 타입을 변형하거나 새로운 타입을 생성하는 데 매우 유용하다. 이 글에서는 TypeScript의 핵심 타입 유틸리티와 문자열 조작용 타입 도구들을 깊이 있게 살펴본다.

1. Awaited<T>: Promise 중첩 해제

비동기 작업에서 최종적으로 반환되는 값을 추출할 때 사용된다. 중첩된 Promise도 재귀적으로 처리한다.

type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number
type C = Awaited<boolean | Promise<number>>; // boolean | number

구현은 조건부 타입과 infer를 활용해 then 메서드의 콜백 인자를 추론한다.

2. ConstructorParameters<T>: 생성자 파라미터 추출

클래스 또는 생성자 함수의 인자 타입을 튜플로 반환한다.

class Point {
  constructor(public x: number, public y: number) {}
}

type PointArgs = ConstructorParameters<typeof Point>; // [x: number, y: number]

내장 생성자에도 적용 가능하다:

type ErrorArgs = ConstructorParameters<ErrorConstructor>; // [message?: string]

3. Exclude<T, U>: 유니온에서 특정 타입 제거

T에서 U에 할당 가능한 모든 타입을 제거한다.

type T1 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'
type T2 = Exclude<string | number | null, null>; // string | number

조건부 타입을 기반으로 구현되며, never는 유니온에서 자동 제거된다.

4. Extract<T, U>: 유니온에서 특정 타입 추출

T에서 U에 할당 가능한 타입만 남긴다.

type T1 = Extract<'a' | 'b' | 'c', 'a' | 'd'>; // 'a'
type T2 = Extract<Function | string, Function>; // Function

5. InstanceType<T>: 인스턴스 타입 추출

생성자 함수가 반환하는 인스턴스의 타입을 얻는다.

class User {
  name = '';
}

type UserInstance = InstanceType<typeof User>; // User
type RegExpInstance = InstanceType<RegExpConstructor>; // RegExp

6. NonNullable<T>: null/undefined 제거

유니온 타입에서 nullundefined를 제거한다.

type T = NonNullable<string | null | undefined>; // string

실제 구현은 T & {}로, 객체 타입이 아닌 값은 필터링된다.

7. Omit<T, K>: 객체에서 속성 제거

객체 타입에서 지정된 키를 제외한 나머지 속성만 남긴다.

interface Config {
  host: string;
  port: number;
  timeout?: number;
}

type BasicConfig = Omit<Config, 'timeout'>; // { host: string; port: number; }

PickExclude를 조합해 구현된다.

8. OmitThisParameter<T>: 함수의 this 파라미터 제거

함수 타입에서 명시적 this 매개변수를 제거한다.

function greet(this: { name: string }) {
  return `Hello, ${this.name}`;
}

type PlainGreet = OmitThisParameter<typeof greet>; // () => string

9. Parameters<T>: 함수 파라미터 추출

함수의 인자 타입을 튜플로 반환한다.

declare function fetchData(url: string, options: RequestInit): Promise<any>;

type FetchArgs = Parameters<typeof fetchData>; // [url: string, options: RequestInit]

10. Partial<T>: 모든 속성을 선택적(optional)으로

객체의 모든 속성을 ? 로 감싸 선택적으로 만든다.

interface UserForm {
  email: string;
  password: string;
}

type PartialForm = Partial<UserForm>; // { email?: string; password?: string; }

11. Pick<T, K>: 객체에서 특정 속성만 선택

지정된 키만 포함하는 새 객체 타입을 생성한다.

type NameOnly = Pick<UserForm, 'email'>; // { email: string }

12. Readonly<T>: 모든 속성을 읽기 전용으로

객체의 모든 속성에 readonly를 적용한다.

type ImmutableUser = Readonly<{ id: number; name: string }>;
// { readonly id: number; readonly name: string; }

반대로 수정 가능하게 만들려면 다음과 같이 사용할 수 있다:

type Mutable<T> = { -readonly [K in keyof T]: T[K] };

13. Record<K, T>: 키-값 매핑 객체 생성

지정된 키 집합과 값 타입으로 객체 타입을 정의한다.

type HttpStatus = Record<200 | 404 | 500, string>;
// { 200: string; 404: string; 500: string; }

14. Required<T>: 모든 속성을 필수로

Partial의 반대 개념으로, 선택적 속성을 모두 필수로 만든다.

interface Options {
  debug?: boolean;
  retries: number;
}

type StrictOptions = Required<Options>; // { debug: boolean; retries: number; }

-? 문법을 사용해 옵셔널 마커를 제거한다.

15. ReadonlyArray<T>: 읽기 전용 배열

배열 요소 수정이나 변경 메서드 사용을 금지한다.

const items: ReadonlyArray<string> = ['a', 'b'];
// items.push('c'); // ❌ 오류

16. ReturnType<T>: 함수 반환 타입 추출

함수의 반환 타입을 추론한다.

function createId(): string {
  return crypto.randomUUID();
}

type IdType = ReturnType<typeof createId>; // string

17. ThisParameterType<T>: 함수의 this 타입 추출

함수 시그니처에서 명시된 this 타입을 반환한다.

function log(this: Console, msg: string) {
  this.log(msg);
}

type ThisTypeOfLog = ThisParameterType<typeof log>; // Console

18. ThisType<T>: this 타입 힌트 제공

타입 체크를 위해 this의 예상 타입을 명시적으로 지정한다. noImplicitThis 옵션이 활성화되어야 효과적이다.

interface ApiContext {
  baseUrl: string;
  fetch: (path: string) => Promise<any>;
}

const apiMethods: ThisType<ApiContext> & { [key: string]: Function } = {
  getUser(id: string) {
    return this.fetch(`/users/${id}`); // ✅ this는 ApiContext 타입으로 간주
  }
};

문자열 조작용 타입 유틸리티

TypeScript 4.1+부터 제공되는 문자열 리터럴 타입 변환 도구는 템플릿 리터럴 타입과 함께 강력한 타입 계산을 가능하게 한다.

  • Uppercase<S>: 모든 문자 대문자 변환
    type T = Uppercase<'hello'>; // "HELLO"
  • Lowercase<S>: 모든 문자 소문자 변환
    type T = Lowercase<'HELLO'>; // "hello"
  • Capitalize<S>: 첫 글자만 대문자
    type T = Capitalize<'hello'>; // "Hello"
  • Uncapitalize<S>: 첫 글자만 소문자
    type T = Uncapitalize<'HELLO'>; // "hELLO"

이러한 도구들은 API 경로 생성, 이벤트 핸들러 이름 규칙 정의 등 다양한 메타프로그래밍 시나리오에서 유용하게 사용된다.

태그: TypeScript UtilityTypes TypeSystem

8월 18일 10:55에 게시됨