기본 패턴
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