숏컷 코드
function format(value: number): string;
function format(value: Date): string;
function format(value: number | Date): string {
return value instanceof Date ? value.toISOString() : value.toFixed(2);
}오버로드 구조
overload 계열에서 먼저 봐 둘 기본형은 아래입니다.
- overload 시그니처 여러 줄
- 구현 시그니처 한 줄
- union 하나로 끝나는 함수
- call signature가 들어간 interface
- call signature 여러 줄로 overload를 표현한 interface
1) 호출 형태가 분명히 여러 개면 overload
하나의 함수가 서로 다른 입력 shape를 받고, 호출자에게 그 경우들을 명확히 보여 주고 싶다면 overload가 맞습니다.
function parse(input: string): number;
function parse(input: number): string;호출자는 구현보다 이 공개 시그니처들을 먼저 읽게 됩니다.
function parse(input: string): number;
function parse(input: number): string;
function parse(input: string | number): number | string {
return typeof input === "string" ? Number(input) : String(input);
}
parse("12");
parse(12);2) 구현 시그니처는 모든 경우를 받아야 한다
overload를 여러 개 적더라도 실제 함수 본문은 모든 케이스를 처리할 수 있는 더 넓은 시그니처 하나를 가집니다.
function format(value: number): string;
function format(value: Date): string;
function format(value: number | Date): string {
return value instanceof Date ? value.toISOString() : value.toFixed(2);
}그래서 overload 설계에서는 "호출용 시그니처"와 "구현용 시그니처"를 분리해서 생각해야 합니다.
3) 단순 union 인자로 충분하면 overload를 줄인다
입력 차이가 크지 않고 반환 타입도 동일하다면 overload보다 union이 더 단순하고 읽기 쉬운 경우가 많습니다.
function format(value: number | Date): string {
return value instanceof Date ? value.toISOString() : value.toFixed(2);
}즉 overload는 "가능해서 쓴다"보다 "호출자 경험이 실제로 더 좋아지는가"로 판단하는 편이 좋습니다.
4) 함수 객체를 모델링하면 call signature
함수 자체에 프로퍼티가 붙는 API를 표현해야 하면 interface 안의 call signature가 자연스럽습니다.
interface Formatter {
(value: number): string;
label: string;
}이 패턴은 라이브러리 함수, 팩토리 함수, callable object 모델링에서 자주 보입니다.
interface Parse {
(value: string): number;
(value: number): string;
}즉 overload는 함수 선언문에만 있는 문법이 아니라, call signature가 여러 줄 들어간 타입으로도 표현할 수 있습니다.
5) overload를 늘릴수록 API 유지 비용도 커진다
새 케이스가 추가될 때 공개 시그니처와 구현 시그니처를 함께 관리해야 하므로, 정말 필요한 경우에만 쓰는 편이 좋습니다.
언제 분리할까
overload를 고를 때 볼 점
- 호출 형태가 여러 개로 분명하다: overload
- 반환 타입과 흐름이 단순하다: union 인자 우선 검토
- 구현은 모든 경우를 처리해야 한다: 넓은 구현 시그니처
- 함수에 프로퍼티도 붙는다: call signature
- overload가 너무 많아진다: API를 다시 단순화할지 검토
주의할 점
오버로드가 필요 없는 문제까지 남발하면 오히려 API 읽기가 어려워집니다. 단순 union 인자와 반환 타입으로 충분한지 먼저 보는 편이 좋습니다.
// 여러 공개 호출 계약이 정말 필요한지 먼저 판단
function format(value: number | Date): string {
return value instanceof Date ? value.toISOString() : value.toFixed(2);
}
// ❌ overload는 많은데 호출자가 실제 이득을 못 봄
function id(value: string): string;
function id(value: number): number;
function id(value: string | number) {
return value;
}
// ✅ union 하나면 충분하면 더 직접적으로 유지
function id2(value: string | number) {
return value;
}참고 링크
1 sources