it공부 (개념)/javascript

다형성을 구현하는방법: 호출 시그니쳐와 함수오버로딩 (타입스크립트 예제). polymorphism, call signature, function overloading, typescript

cantor 2023. 2. 6. 09:55

4줄 요약)

 

1. 다형성은  "객체지향"의 특성 중 하나로, 한 가지 형태로 여러 가지 기능을 수행하는 특성을 뜻한다.

2. 호출 시그니쳐는 함수가 받아들이는 인자의 타입 및 형태이다.

3. 함수 오버로딩은 한개의 함수가 여러 개의 호출 시그니쳐 및 그에 대응되는 실행기능을 갖는 것을 말한다.

 

4. 하나의 이름을 갖는 함수가 여러 호출시그니처를 가짐으로써 "다형성" 특성이 구현된다.

 

 

 

prototype(프로토타입)과 객체지향 프로그래밍: Typescript Decorator를 위한 Javascript(자바스크립트) 사전

Prototype?(프로토타입)의 의미 사전적 의미: proto: 원래의, 원시적인 + type: 형태, 유형, 카테고리 prototype: 원래의 형태, 원형, 임시 모델 Prototype in javascript(자바스크립트, 이하 JS): 객체의 특징, 행동

batcave.tistory.com

 

위의 포스팅의 말미에서 객체지향의 특성에 대해 간단하게 설명했었다.

 

이 게시글에선 polymorphism(다형성)에 대해 좀더 알아보고 

call signature(호출 시그니쳐)와 function overloading(함수 오버로딩)을 통해 어떤 식으로 다형성이 구현되는 모습을 살펴보겠다.

 

 

 

 

polymorphism(다형성)?

폴리모피즘이라는 단어가 생소할 수 있으니, 사전적 정의를 살펴보자.

 

    • polymorphism 의 사전적 의미


      poly: 여러가지의, 여러 개의

      폴리는 여러개를 뜻하는 접두어이다.
      화학, 생물학을 통해 우리는 이미 폴리~~ 단어를 많이 들어봤다.

      polypeptide(폴리펩타이드): 단백질: 펩타이드결합이 여러 개 있다는 뜻이다.
      polyester(폴리에스테르): 석유로 만드는 옷감 에스테르결합이 여러 개 있다는 뜻이다.


      morphism: 형태, 상태변화
      morph(모프): 변화하다.

      metamorphosis(변신): 프란츠 카프카의 소설 "변신"의 영어제목.
      워크래프트 3 악마사냥꾼의 궁극기 "탈태" 또는 "메타몽"의 원래 이름


      이처럼 polymorphism은 다소 생소 할 수 있지만
      사실 poly와 morph는 이미 여러번 접해서 친숙한 영단어들이다.

      소싯적에 판타지 소설좀 읽은 분은 폴리모피즘 자체가 이미 익숙할 것이다.
      "폴리모프"가 드래곤따위의 대단한 존재가 사용하는 변신스킬 이름으로 종종 등장하기 때문이다.



  • 프로그래밍에서의 polymorphism:


    polymorphism(다형성):
    같은 이름을 사용하는 객체가 다른 특성이나 행동을 보유할 수 있는 특성.

    ex)

    "hi"+ "hi" === "hihi"
    두 문자열을 이은 하나의 문자열을 만들어주는 연산

    6 + 7 === 13
    두 숫자를 더해주는 연산

    위의 예시에서 "+" 연산자는 피연산자의 타입에 따라 전혀 다른 기능을 수행하고 있다.

    이렇게 같은 이름으로 여러가지 다른 기능을 갖고 있는 것을 다형성이라 한다.

 

Call signature(호출 시그니쳐)



함수를 호출할 때, 대입되어야하는 인자들의 타입 및 형태.

일반적으로 타입스크립트에선 함수코드에 마우스커서를 올리면 호출 시그니쳐를 살펴볼 수 있다.

함수명뒷부분이 호출 시그니쳐이다. 혹은 함수명까지 포함하기도 한다..

 

 

호출시그니쳐 분리및 함수 오버로딩:

 

타입스크립트에서는 함수를 선언할 때, 매개변수의 타입을 꼭 지정해주어야 한다.

하지만 "interface"나 "type" 선언을 통해 호출시그니쳐를 함수 선언에서 분리해 줄 수 있다.

 

 

"type"을 이용해 호출시그니처를 먼저 정의하기.

// 화살표 함수의 타입을 지정했다.
type ArrowCS = (a: number, b: number) => number;


//변수에 함수를 저장했다. a와 b에는 타입을 써주지 않아도 된다.
const ArrowAdd: ArrowCS = (a, b) => a + b


// 타입지정은 화살표함수로 했지만, 일반 함수도 type ArrowCS를 사용할 수 있다.
const NormalAdd: ArrowCS = function (a,b) {
                                           return a+b
                                           };

"interface"를 이용해 호출시그니처를 먼저 정의하기.

                         
interface NormalCS {
    (arg1: string, arg2: number): number;
}

//일반 함수
const InterfaceFunction: NormalCS = function (arg1, arg2) {return arg2;};

//화살표 함수
const InterfaceArrow: NormalCS = (arg1, arg2) => arg2;

  

위의 두 코드처럼 호출시그니처를 분리하는 함수는

"function"키워드로 선언을 시작하지 않고, const나 let을 통해 선언한 변수에 함수를 저장하는

"익명함수"로만 구현할 수 있다.

 

 

호출 시그니처를 이용한 함수 오버로딩 구현

 

1. 인자의 개수가 여러 개인 경우

type ForOverloading = {
    
    (a: number, b: number): number,
    (a: number, b: number, c:number): number

}

//인자의 개수가 세개인경우 세개를 모두 더한다.
const newAdd: ForOverloading = (a, b, c?:number) => {
    if (c) return a + b + c
    return a + b;
}


//인자의 개수와 상관없이 받는 함수

type ForOverloading = {
    
    (a: number, b: number): number,
    (a: number, b: number, ...args: number[]): number

}

const newAdd: ForOverloading = (a, b, ...args: number[]) => {
    let sum = a + b;
    args.forEach(arg => sum += arg);
    return sum;
};

 

예시 2: 인자의 타입이 여러 개인 경우


type SpecialAdd = (a: number | string, b: number | string) => number | string;

//SpecialAdd 함수는 number 두개를 입력 받을때와
// string두개를 입력받을때 서로다르게 동작한다.

const specialAdd: SpecialAdd = (a, b) => {
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
else if(typeof a ==="string" && typeof b ==="string") {
return a + b;
}
else {
throw TypeError;
}
}

 

 

+@

 

제네릭을 이용하면 더 쉽게 구현할 수 있다.

 

 

Generic(제네릭)이란? 개념 및 Typescript 예제. "any 쓰지마세요"

Generic? 사전적 의미: 일반적인, 추상적인, 포괄적인 반의어) 구체적 (specific) Generic in TypeScirpt(타입스크립트, 이하 TS) TS의 "유연한 타입 제약"을 가능케하는 문법. 하나의 함수, 또는 클래스 코드가

batcave.tistory.com

 

type SuperPrint = {
    <T>(arr: T[]):void
}

const superPrint: SuperPrint = (arr) => {
    arr.forEach(i => console.log(i))
}

superPrint([1,2,3]) // number[]
superPrint(["a", "b", "c"]) // string[]
superPrint([1,2, "a", true]) // 이것도전부 타입을 잡아준다. 
//사진참고

 

 

 

 

읽어주셔서 감사합니다.
오탈자 및 오류를 발견할시 댓글로 지적해주세요.

 


내용참고: https://www.youtube.com/watch?v=FotK-GR0kLI&embeds_euri=https%3A%2F%2Fnomadcoders.co%2F&embeds_origin=https%3A%2F%2Fnomadcoders.co&source_ve_path=MjM4NTE&feature=emb_title

 

썸네일 출처

Variable icons created by Parzival’ 1997 - Flaticon