TypeScript, 함수 오버로딩을 스마트하게 대체하는 “매개변수 동적 추론”

하나이 함수에 대해서 첫번째로 입력받는 인자의 값에 따라 이후 인자의 타입을 결정할 수 있는 방법입니다. 함수 오버로딩이 아닌 TypeScript 본연의 타입 기능을 이용하는 방법으로 함수 오버로딩보다 더욱 작성하기 쉽고 똑똑합니다. 예를들어 emit라는 함수를 다음처럼 정의합니다.

type EventMap = {
  click: { x: number; y: number };
  hover: { elementId: string };
  keyPress: { key: string; code: number };
};

// Key를 제네릭으로 받아 EventMap[Key]를 Payload 타입으로 자동 추론합니다.
function emit(eventName: K, payload: EventMap[K]) {
  console.log(`Event: ${eventName}`, payload);
}

emit의 첫번째 값에 따라 두번째 인자의 타입이 다르게 결정됩니다. 해당 타입들은 위의 EventMap 타입에 정의되어 있습니다. 이제 다음처럼 emit 함수를 이용할 수 있습니다.

emit('click', { x: 10, y: 20 });        // ✅ 정상 작동
emit('click', { elementId: 'btn' });    // ❌ 타입 에러! click은 x, y가 필수입니다.
emit('hover', { elementId: 'header' }); // ✅ 정상 작동 (elementId 오타 시 감지)

그러나 emit 함수 구현부에서 첫번째 인자인 eventName의 값에 따라 payload의 타입을 결정해서 사용할 수 있어야 합니다. 예를들어 eventName이 ‘click’이라면 payload.x가 가능해야 합니다. 하지만 위의 방법으로는 안됩니다. 다른 방법은 다음과 같으며 TypeScript 코드로써 보다 더 쉽고 직관적입니다.

type EventMap =
  | {
    eventName: "click";
    payload: { x: number; y: number };
  }
  | {
    eventName: "hover";
    payload: { elementId: string };
  }
  | {
    eventName: "keyPress";
    payload: { key: string; code: number };
  };

function emit(event: EventMap) {
  if (event.eventName === "click") {
    event.payload.x; // ✅
    event.payload.y;
  }

  if (event.eventName === "hover") {
    event.payload.elementId; // ✅
  }
}

emit({ eventName: 'click', payload: { x: 10, y: 20 } });

결국 함수 오버로딩을 스마트하게 대체하는 “매개변수 동적 추론” 방식은 크게 의미가 없습니다. 🙂

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다