노트

함수 오버로드와 시그니처

Function Overloads

프런트엔드#ts · 연결된 개념 5개

쉽게 말하면

함수 오버로드는 자판기 하나에 동전을 넣으면 이것, 카드를 대면 저것처럼 넣는 방식별 안내문을 여러 장 붙이는 거예요. 기계는 하나지만 쓰는 사람은 무엇을 넣었느냐에 따라 받을 결과 타입을 정확히 알아요.

비유가 깨지는 곳 자판기 속 실제 구조인 구현 시그니처는 밖에서 안 보여요. 호출하는 쪽은 위의 오버로드 선언만 보니 오버로드는 두 개 이상 두고, 인자 개수와 반환 타입이 같다면 유니언 매개변수 하나가 나아요.

함수 오버로드(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 매개변수(화살표 함수에선 불가)

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 매개변수 객체 만들기

    여러 함수에 늘 함께 넘겨지는 값 묶음(데이터 뭉치, Data Clumps)을 하나의 객체로 묶어 넘기는 리팩터링.

  • 매핑된 타입과 keyof

    매핑된 타입(Mapped Types)은 기존 타입의 키를 하나씩 돌며 새 타입을 만드는 문법([K in keyof T]: …)이다. keyof T는 객체 타입의 키 유니언을, T[K](인덱스 접근 타입, Indexed Access Type)는 그 키의 값 타입을 꺼낸다.

  • 기본형 집착

    전화번호·금액·우선순위 같은 도메인 개념을 끝까지 문자열이나 숫자로만 다루는 냄새. 같은 검증과 포맷 코드가 여기저기 반복되고, 문자열로 모든 걸 표현하는 "stringly typed" 코드가 된다.

  • 제네릭

    제네릭(Generics)은 타입을 매개변수처럼 받아, 여러 타입에 같은 로직을 재사용하면서도 타입 정보를 잃지 않게 하는 기능이다.

  • type과 interface

    type(타입 별칭, Type Alias)과 interface는 둘 다 타입에 이름을 붙이는 방법이다. 객체 모양을 정의할 때는 대부분 바꿔 써도 되지만, 확장 방식과 표현 범위가 다르다.

보기 옵션