오버로드 해석

호출자는 오버로드를 보고, 실행은 하나의 구현이 맡는다

함수 오버로딩은 여러 호출 형태를 문서처럼 드러내면서도 실제 코드는 하나만 둔다. 그래서 선택된 시그니처와 구현 시그니처의 포괄성이 함께 맞아야 한다.

1

인자 확인

호출에 들어온 타입과 개수를 선언된 목록과 비교한다.

2

시그니처 선택

더 구체적인 오버로드가 앞에 있으면 의도한 반환 타입을 얻는다.

3

구현으로 이동

실행되는 함수는 마지막 구현 시그니처 하나뿐이다.

4

타입 가드

본문에서 typeof, Array.isArray 같은 검사로 분기한다.

호출 형태가 선택되는 방식

선언 선택 -> 구현 실행
호출 getLength("abc")
선택되는 선언 input: string
반환 number
실행 경로 구현 함수 안에서 문자열 분기
호출 getLength(["a", "b"])
선택되는 선언 input: string[]
반환 number
실행 경로 같은 구현 함수 안에서 배열 분기
호출

getLength("abc")

호출자는 선언된 오버로드 목록만 보고 반환 타입을 기대한다.

선택
input: string number
input: string[] number

위에서부터 맞는 선언을 찾고, 가장 알맞은 호출 타입을 고른다.

실행

input: string | string[]

런타임에는 구현 하나만 호출되고, 내부 타입 가드가 실제 분기를 맡는다.

오버로드 1

문자열 입력

function getLength(input: string): number;

호출자가 문자열을 넘기면 반환 타입은 number로 바로 확정된다.

오버로드 2

문자열 배열 입력

function getLength(input: string[]): number;

배열 호출도 별도 사용법으로 드러나 문서 역할을 한다.

구현 시그니처

모든 오버로드를 포괄하는 타입

function getLength(
  input: string | string[]
): number {
  return input.length;
}
          

구현 시그니처는 호출자가 직접 보는 타입이 아니라, 선언한 모든 오버로드를 실제로 처리하기 위한 내부 타입이다.

오버로딩

인자에 따라 반환 타입이 달라질 때

`parse(string): number`, `parse(number): string`처럼 호출 형태와 결과 타입의 대응이 중요하면 오버로드가 읽기 쉽다.

유니온

결과가 크게 달라지지 않을 때

내부에서 타입만 좁히면 되고 반환 타입이 하나로 설명되면 `string | number`가 더 간단하다.

구체적인 순서

리터럴 타입이나 좁은 형태를 넓은 타입보다 먼저 선언한다.

포괄 구현

구현 매개변수는 모든 오버로드 인자를 받을 수 있어야 한다.

호출 기준

호출부는 구현 시그니처가 아니라 오버로드 목록만 보고 검사된다.