[TypeScript] 타입 추론 기반의 메타 프로그래밍 패턴

Chan의 기술 블로그·2025년 11월 11일

TypeScript

목록 보기
6/10

이 글은 Chat GPT로 TypeScript를 공부하며 정리한 글입니다.

타입 추론 기반의 메타 프로그래밍 패턴

앞선 글에서는 제네릭과 keyof, Mapped Type, Conditional Type,
그리고 infer를 조합해 타입을 변환하는 기본 패턴을 살펴봤다.

이번 글에서는 이를 확장해
“클래스의 생성자 타입과 인스턴스 타입을 다루는 고급 타입 추론 패턴”을 분석한다.

메타 프로그래밍이란?

메타 프로그래밍(Metaprogramming)은
“코드를 데이터처럼 다루고, 코드 구조를 분석해 새로운 코드를 만들어내는 기법”이다.

TypeScript는 타입 시스템 안에서 이를 구현할 수 있다.
즉, 타입 자체를 계산/분석/변환하는 타입 레벨 메타 프로그래밍이 가능하다.


InstanceType<T> — 생성자의 인스턴스 타입 추출

InstanceType<T>는 클래스 생성자의 인스턴스 타입을 추출하는 유틸리티 타입이다.

class User {
  id: number = 1;
  name: string = "chan";
}

type U = InstanceType<typeof User>;
// U = User
  • typeof User → “클래스 생성자 함수의 타입”
  • InstanceType<typeof User> → 생성자의 반환값(= 인스턴스 타입)

직접 구현해보기

type MyInstanceType<T extends new (...args: any[]) => any> =
  T extends new (...args: any[]) => infer R ? R : never;

구성 분석

구문의미
T extends new (...args: any[]) => any생성자 함수 타입만 받겠다는 제약
new (...args) => infer R생성자의 반환 타입(인스턴스)을 추론
R최종 추출된 인스턴스 타입

예시

class Product {
  constructor(public name: string, public price: number) {}
}

type ProductInstance = MyInstanceType<typeof Product>;
// ProductInstance = Product

ConstructorParameters<T> — 생성자 매개변수 타입 추출

ConstructorParameters<T>
클래스 생성자의 인자 타입들을 튜플 형태로 추출하는 타입이다.

class User {
  constructor(public name: string, public age: number) {}
}

type Params = ConstructorParameters<typeof User>;
// Params = [string, number]

직접 구현해보기

type MyConstructorParameters<T extends new (...args: any[]) => any> =
  T extends new (...args: infer P) => any ? P : never;

구성 분석

구문의미
new (...args: infer P)생성자 인자 목록을 P로 추론
P최종 매개변수 타입 튜플
never생성자 타입이 아닐 때

예시

class Product {
  constructor(public id: number, public name: string) {}
}

type ProductArgs = MyConstructorParameters<typeof Product>;
// [number, string]

함수 vs 클래스 타입 추출 비교

TypeScript는 "함수"와 "클래스 생성자"를 각각 다른 타입으로 취급한다.
아래는 그 차이를 정리한 표다.

대상내장 타입추출 대상예시
함수(Function)Parameters<T>인자 타입 목록(x: number) => void[number]
함수(Function)ReturnType<T>반환 타입() => stringstring
클래스(Class)ConstructorParameters<T>생성자 인자 목록new (id: number)[number]
클래스(Class)InstanceType<T>인스턴스 타입typeof UserUser

💡 즉,
ConstructorParametersInstanceType은 “클래스 버전의 Parameters/ReturnType”이다.


실무 예시 — 타입 안전한 클래스 인스턴스 생성 함수

function createInstance<T extends new (...args: any[]) => any>(
  ctor: T,
  ...args: ConstructorParameters<T>
): InstanceType<T> {
  return new ctor(...args);
}

활용

class User {
  constructor(public name: string, public age: number) {}
}

const user = createInstance(User, "chan", 29);
// user: User
  • 인자 타입 자동 추론 → ConstructorParameters<T>
  • 반환 타입 자동 추론 → InstanceType<T>
  • 런타임과 타입 정보가 정확히 일치함

응용 예시 — 클래스 기반 API Client Factory

class ApiClient {
  constructor(private baseUrl: string) {}
  get(path: string) {
    return `GET ${this.baseUrl}/${path}`;
  }
}

function wrapClient<T extends new (...args: any[]) => any>(Client: T) {
  return function (...args: ConstructorParameters<T>): InstanceType<T> {
    const instance = new Client(...args);
    console.log("클라이언트 생성됨:", instance);
    return instance;
  };
}

const createApi = wrapClient(ApiClient);
const api = createApi("https://example.com");
// api: ApiClient

api.get("posts"); 
// "GET https://example.com/posts"

React Hook Factory, Service Locator, API Wrapper 같은 패턴에서 자주 활용되는 구조이다.


추상 클래스 타입 정의 — AbstractConstructor

추상 클래스도 ‘생성자 타입’으로 다룰 수 있다.

type AbstractConstructor<T = any> = abstract new (...args: any[]) => T;

abstract class BaseService {
  abstract execute(): void;
}

class UserService extends BaseService {
  execute() {
    console.log("User Service 실행");
  }
}

function runService<T extends AbstractConstructor<BaseService>>(Ctor: T) {
  const instance = new Ctor();
  instance.execute();
}

runService(UserService); // OK

마무리

InstanceType<T>ConstructorParameters<T>
단순 유틸리티 타입이 아니라
“클래스의 타입 구조를 분석하고 재사용하는 메타 프로그래밍 기법의 핵심”이다.

이를 이해하면:

  • 타입 안전한 팩토리 함수
  • 의존성 주입(DI) 컨테이너
  • 서비스 래퍼(wrapper)
  • 클래스 기반 API 클라이언트
  • 라이프사이클 기반 객체 관리자

같은 구조를 모두 타입 레벨에서 안전하게 설계할 수 있다.

요약 표

개념역할예시
Parameters<T>함수 인자 타입 추출(x: number) => void[number]
ReturnType<T>함수 반환 타입 추출() => stringstring
ConstructorParameters<T>생성자 인자 추출new (id: number)[number]
InstanceType<T>인스턴스 타입 추출typeof UserUser

💡 한 문장 요약
“함수와 클래스의 내부 타입 구조를 분석하고 자동으로 추출하는 것 — 그것이 TypeScript 메타 프로그래밍의 핵심이다.”

profile
퍼블리셔에서 프론트앤드로 전향하기

0개의 댓글