본문 바로가기

내일배움캠프_개발일지/TypeScript 연습

TypeScript 연습 <1> -5-

________________________________________________________________________

 

TypeScript 에서 함수를 다뤄보자 -2-

 

 

 

< overloading 오버로딩 >

< overloading 오버로딩 - 실제로 우리가 만나게 될 예시 >

 

 

오버로딩이 중요한 점.

실제로 개발에 들어갔을 때 그리 많은 ‘오버로딩 된 함수’ 를 작성 하지는 않을거야.

대신, 난 아마 대부분에 시간을 다른 사람들이 만든 외부 라이브러리를 사용하는데에 투자하게 될 거야.

그러한 패키지나 라이브러리들은 오버로딩을 매우 많이 사용해.

즉, 오버로딩에 대한 개념이 잡혀 있어야지, 다른 사람의 코드들도 잘 읽어낼 수 있다는 뜻.

 

 

1.

_________________________

< 오버로딩 >

 

 

이전 시간에 봤던 call signatures 를 다시 살펴보자.

——

type Add = (a:number, b:number) => number // signatures

 

const add : Add = (a, b) => a + b

——

=> 우리가 타입스크립트에게 add 라는 함수가 어떻게 호출되는 건지를 설명해 주는 부분이지.

 

 

 

위와 같은 방식은 단축키와도 같아. 가장 빠르고 간단하게 signatures 를 만드는 방법이지.

아래처럼 만들 수도 있어.

——

type Add2 = {

    (a:number, b:number) : number

}

——

=> 이런 방법이 존재하는 이유는 오버로딩 때문.

오버로딩은 함수가 여러 개의 call signatures 를 가지고 있을 때 발생시켜.

그냥 여러 개가 아니라 서로 다른 여러 개의 call signatures 를 가졌을 때.

 

 

다음과 같이 signatures 타입이 여러 개의 signatures 를 가진다고 가정해보자. 조금 바보같은 예시 이긴 한데, 어쨌든.

——

type Add2 = {

    (a:number, b:number) : number

    (a:number, b:string) : number

}

const add2 : Add2 = (a, b) => a + b // 에러 발생. Operator '+' cannot be applied to types 'number' and 'string | number'

——

=> 에러가 발생해. 왜? 

넘버인 a 와 문자일수도, 숫자일수도 있는 b 를 합칠 수는 없다고 설명하고 있어.

즉 두 가지의 signatures 가 곂치면서 b 는 number 일 수도, string 일 수도 있게 된거야.

따라서 아래와 같이 먼저 확인을 해줘야 해.

 

——

type Add2 = {

    (a:number, b:number) : number

    (a:number, b:string) : number

}

const add2 : Add2 = (a, b) => {

    if (typeof b === "string") {

        return a

    }

    return a + b

}

——

=> 이렇게 if 로 분기를 해주면 두 가지 signatures 를 모두 만족시킬 수는 있어.

 

 

— 추가 —

——

const add2 : Add2 = (a, b) => { // 에러 발생

    if (typeof b === "string") {

        return a

    }

    if (typeof b === "number") {

        return a + b

    }

}

——

=> 이처럼 작성했을 경우,

add2 에 값을 할당할 수 없다면서 에러가 떠. 왜? 함수 안에서 모든 경우에서 return 을 하는 것은 아니다라면서.

(parameter) b: string | number >> b의 시그니처 설명인데,  그냥 이렇게 명시해주는 것과 시그니처로 명시해주는 건 다른가봐.

(b: string | number) 이렇게 타입을 명시해 줬을 때는 if 문 두 개로 오류가 안났는데, 이 경우에는 에러가 발생.

 

따라서

——

const add2 : Add2 = (a, b) => {

    if (typeof b === "string") {

        return a

    }

    if (typeof b === "number") {

        return a + b

    }

    return a

}

——

이런 식으로 모든 상황에서 어떻게든 return 이 되도록 고쳐줘야 해.

 

 

허나 위의 예시는 그리 좋은 예시가 아니야. 

왜? 위처럼 signatures 를 작성할 수 있는 건 극히 제한된 소수의 경우에서만 가능해서.

따라서 사실상 의미 없는 예시이지만, 오버로드의 예시를 보여줄 수 있지.

 

다시 말하자면, 오버로딩은 여러 call signatures 가 있는 함수에서 발생하는 현상.

이 경우 add2 라는 함수가 Add2 라는, 다수의 signatures 를 지닌 타입을 취하게 되었다는 것.

 

 

 

 

 

 

2.

_________________________

< 오버로딩 - 자주 등장하는 예시 >

 

 

이제 실제로 우리가 겪을 만한 오버로딩 예시를 들어보자.

——

type Config = {

    path: string,

    state: object

}

 

type Push = {

    (path: string) : void,

    (config: Config): void

}

 

const push: Push = (config) => {

    if (typeof config === "string") {

        console.log(config);

    } else {

        console.log(config.path)

    }

}

——

=> 해당 xxx.push() 라는 건 react 에서 해당 주소의 페이지를 랜더해줄 때 사용하는 메소드를 예시로 든 거야.

 

node.js 에서 res.render() 를 예시로 들어볼까?

res.render(‘/home’) 이런 경우가 있는 가 하면 res.render(‘/home’,  {data: data}) 이렇게 data 를 함께 보내주는 경우도 있었지.

 

즉, render() 라는 함수에 매개변수로 path 만 들어가냐, 아니면 추가적으로 {} 도 함께 들어가냐에 따라 다른 시그니쳐가 적용되었던 거야.

즉 오버로딩이 발생했다는 거지.

 

위의 예시에서 (config) => {} 에서 매개변수 이름 config 는 중요하지 않아.

중요한 건, 저 매개변수에 들어있는 값이 string 이면  (path: string) : void 에 해당하고,

그 외이면  (config: Config): void 에 해당하게 된다는 거지.

 

이 경우 

push(“/home“) 이냐

push({ path:”/home”, state: {data: result} }) 이냐

이거지.

 

매개변수로 들어온 값이 string 이냐, 아니면 Config 타입의 객체냐에 따라서 다르게 오버로딩을 해준 다는 것.

이것이 핵심.

 

*** 시그니쳐일 경우 선언되는 변수에 type 이 붙게 되고,

그냥 함수의 리턴 타입을 명시하고 십다면 함수의 () 뒤에 type 이 붙는다… 맞나?

 

 

 

위의 예시에서는 각각의 call signatures 들이 하나의 매개변수 만을 받고 있는 경우.

그렇다면, 각각의 시그니쳐들이 각기 다른 갯수의 매개변수를 받고 있을 때는 어떻게 명시 하면 좋을까?

 

——

type Add3 = {

    (a:number, b:number) : number,

    (a:number, b:number, c:number) : number

}

 

const add3 : Add3 = (a, b, c?:number) => {

    if (c) return a + b + c;

    return a + b;

}

 

add3(1, 2);

add3(1, 2, 3);

——

=> (a, b, c?:number) 이렇게 옵션을 주는거지. 옵셔널 타입 마냥.

그리고 내부에서는 c 가 있냐 없냐에 따라 return 을 달리 해주면 오류는 발생하지 않아.

 

사실 파라미터의 갯수가 다른 경우에 대응하여 시그니쳐를 여러 개 작성한다는 경우는 많이 발생하지 않아.

이것 보다는 이전 예시인 path, object 쪽이 우리가 많이 만나게 예시.

'내일배움캠프_개발일지 > TypeScript 연습' 카테고리의 다른 글

TypeScript 연습 <1> -7-  (0) 2023.01.30
TypeScript 연습 <1> -6-  (0) 2023.01.27
TypeScript 연습 <1> -4-  (1) 2023.01.25
TypeScript 연습 <1> -3-  (0) 2023.01.25
TypeScript 연습 <1> -2-  (1) 2023.01.20