TypeScript객체와 함수

함수 overload와 call signature

여러 호출 방식을 하나의 함수에 표현할 때 overload를 언제 쓰고, union이나 제네릭과는 어떻게 구분할지 정리합니다.

마지막 수정 2026년 3월 22일

기본 패턴

ts
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(a: number, b?: number, c?: number): Date {
  return b !== undefined && c !== undefined
    ? new Date(c, a, b)
    : new Date(a);
}

설명

  • overload는 "같은 이름의 함수가 여러 호출 형태를 가진다"는 사실을 타입 시스템에 표현하는 방법입니다. 호출 인수 개수나 조합에 따라 API 의미가 달라질 때 유용합니다.
  • 가장 흔한 예시는 인수 개수에 따라 다른 동작을 하는 함수입니다. timestamp 하나를 받거나, year/month/day 세 값을 받는 경우처럼 호출 모양이 명확히 구분되면 overload가 잘 맞습니다.
  • 하지만 모든 경우에 overload가 답은 아닙니다. 단순히 입력 타입이 union일 뿐이고 반환 타입도 비슷하다면 overload보다 union 매개변수나 제네릭이 더 단순하고 읽기 쉽습니다.
  • 중요한 점은 implementation signature는 외부 호출용 계약이 아니라 내부 구현용 시그니처라는 것입니다. 즉 실제로는 넓게 받고, 위쪽 overload signature가 사용자에게 보이는 API가 됩니다.
  • 좋은 overload 설계는 "호출하는 사람이 어떤 형태가 가능한지 바로 이해할 수 있는가"가 핵심입니다. 가능하면 모양이 분명한 경우에만 쓰는 편이 좋습니다.

빠른 정리

상황더 잘 맞는 선택
인수 개수/조합에 따라 호출 모양이 달라짐overload
단순히 여러 타입을 하나로 받음union 매개변수
입력과 출력 관계를 보존해야 함제네릭
사용자에게 여러 API 모양을 명확히 보여주고 싶음overload
구현을 단순하게 유지하고 싶음union 또는 제네릭 우선 검토

주의할 점

overload를 너무 많이 만들면 함수 사용법은 화려해 보여도 실제 유지보수는 더 어려워집니다. 호출 형태 차이가 분명하지 않다면 union이나 옵션 객체가 더 나은 설계일 수 있습니다.

참고 링크

1 sources