함수 오버로드(Function Overloads)는 구현 하나 위에 호출 방식별 시그니처를 여러 개 선언해, 인자 조합에 따라 정확한 반환 타입이 추론되게 하는 TypeScript 기능이다.
function add(a: number, b: number): number
function add(a: string, b: string): string
function add(a: number | string, b: number | string) { // 구현 시그니처
return typeof a === 'string' || typeof b === 'string' ? `${a}${b}` : a + b
}
add('Max', ' Kim').split(' ') // 반환이 string으로 추론됨- 구현 시그니처(Implementation Signature)는 밖에서 보이지 않는다. 호출하는 쪽은 위의 오버로드 선언만 본다. 그래서 오버로드는 항상 두 개 이상 둔다
- 인자 개수와 반환 타입이 같다면 오버로드보다 유니언 매개변수 하나가 낫다:
function len(x: string | any[]) - 입력에 따라 반환 타입이 바뀌는 경우는 조건부 타입과 infer로 표현할 수도 있다
- 콜백의 매개변수는, 실제로 인자 없이 부를 일이 없다면 선택적(
?)으로 만들지 않는다
다른 함수 타입 표기
type Fn = (a: string) => void // 함수 타입 표현식(매개변수 이름 필수)
type Describable = { description: string; (n: number): boolean } // call signature: 속성도 가진 함수
type Ctor = { new (s: string): Thing } // construct signature: new로 호출
function filterAdmins(this: User) { return this.admin } // this 매개변수(화살표 함수에선 불가)Function타입은 반환이any라 피하고() => void처럼 구체적으로 쓴다- 반환 타입이
void인 함수 타입에 맞춰 쓰는 함수(문맥적 타이핑, contextual typing)는 값을 돌려줘도 된다. 돌려준 값은 무시되고 호출 결과는void로 취급된다. 그래서push가 숫자를 돌려줘도src.forEach(el => dst.push(el))가 통과한다. 반면 함수 선언이나 함수 식에 직접: void를 적으면 값을 반환할 수 없다.void는undefined와 같은 타입이 아니다 - 함수 타입끼리의 할당 규칙은 공변성과 반공변성, 함수 선언을 바꾸는 리팩터링은 함수 선언 바꾸기과 플래그 인수 참고
출처: TypeScript Handbook - Function Overloads · Return type void