Front_End [JS기반]/타입스크립트

[ 3D Web : Front&Back_Type Script ] 타입스크립트 : 타입스크립트 함수 타입 공부하기.

안다미로 : Web3 & D.S 2024. 11. 27. 18:13

 

 

 

[ 3D Web : Front&Back_Type Script ] 

타입스크립트 : 타입스크립트 함수 타입 공부하기.

 


 

∇ Front & Back _ TypeScript : 타입스크립트 함수 타입 공부하기.

목  차

1. TS의 함수 표현
    1-1 일반적인 함수 정의
    1-2 Call Signature(함수 타입)
2. TS의 매개변수 표현   
    2-1 선택적 매개변수
    2-2 매개변수 초기화
    2-3 나머지(rest) 매개변수
    2-4 네임드 파라미터
3. TS의 콜백/ 중첩 / 고차 함수
    3-1 콜백 함수
    3-2 중첩 함수
    3-3 고차 함수
4. TS의 this 표현
    4-1 명시적 this
5. TS의 함수-오버로딩

 


 

Ⅰ. TS의 함수 표현.


    ※ TS에서 함수를 표현하는 방법은 여러가지가 존재한다고 합니다. (머리가 아플 정도)

         TS로 백*프론트 모두 사용하고,  Nest 프레임워크에서도 언어로 활용되는 만큼, 진짜 제대로 짚고 넘어가보겠습니다.

 

 

       Ⅰ - ⅰ. 일반적인 함수 정의 

                  - TS(JS기반)에서는 일반적으로  함수를 표현하는데에 크게 3가지 표현방법이 있습니다.

                        :  "함수 선언식" // "함수 표현식" // "화살표 함수"

                      [ + 여기에, 매개변수 & 리턴값*타입 만 지정해주면 되니 그렇게 난해하지 않습니다. ]

 

 

                  § 함수 선언식.

//* 함수 선언식
function myFunc1(x: number, y: number): number {
   return x + y;
}

 

 

                  § 함수 표현식.

//* 함수 표현식
let myFunc2 = function (x: number, y: number): number {
   return x + y;
};

 

 

                  § 화살표 함수.

//* 화살표 함수
let myFunc3 = (x: number, y: number): number => {
   return x + y;
};

 


       Ⅰ - ⅱ. Call Signature (함수 타입)

 

            위쪽 코드에서도 나오긴 했는데, 

            변수를 선언할 때,  문자열을 string, 정수배열을 number[]로 표현했듯이

            "함수를 표현하는 타입( ≡함수에서 반환하는 값의 타입) 을 미리 선언 가능합니다.

 

             § "함수 타입"을 미리 선언하고 뒤에 함수식을 붙여넣게되면, 

                      함수 아규먼트에서 타입을 또다시 선언하지 않아도 된다는 특징을 가집니다.

 

//* 변수에 미리 함수 타입을 지정
let myFunc4: (arg1: number, arg2: number) => number;
myFunc4 = function (x, y) {
   return x + y;
}; // 미리 변수에 함수 타입을 지정했기에 대입하는 함수식에 타입을 쓰지않아도 된다.

//* 위의 과정을 한줄로 표현
let myFunc5: (arg1: number, arg2: number) => number = (x, y) => {
   return x + y;
};

 

   **주의할 점!

           - 위에서 설명한 화살표 함수와 헷갈리지 않게 조심해야 합니다.!!

           - 함수 표현식에선, 함수의 리턴 타입을 콜론(:)으로 표현했는데 

                  따로 함수 타입을 선언할 때는 화살표로 리턴 타입을 표현한다는 점에서 주의가 필요합니다!

 

 

      ∫ 함수 타입과 화살표 함수를 섞어서 사용하기.     

let myFunc5: (arg1: number, arg2: number) => number = (x,y) => {return x + y; };

       

   *이런 방식의 이점 4가지,

 

                    1. 타입 안정성 향상.  

                           - 함수 타입을 명시적으로 선언함으로써, TS의 정적 타입 검사를 최대한 활용.

                           - 코드의 안정성을 높이고 런타임 오류를 줄이는 데 도움.

 

                    2. 코드 가독성 개선.

                           - 함수의 목표를 명확히 정의함으로써, 다른 개발자들이 함수의 입*출력 타입을 쉽게 이해 가능.

 

                    3. 화살표 함수의 간결성 

                           - 화살표 함수를 사용함으로써, 더 간결한 문법으로 함수를 정의 가능.

 

                    4. this 바인딩 예측 가능성.

                           - 화살표 함수는 자신만의 this를 생성하지 않아서, 렉시컬 스코프의 this를 사용하므로

                                 this 관련 버그를 줄일 수 있습니다.

 

 

 ▣ " type 별칭 " 및 "인터페이스" 역시 개별적으로 함수타입을 선언하여 사용될 수 있습니다. 

          [ 인터페이스는 함수 타입을, 화살표가 아닌 콜론(:)으로 표현합니다 ]

//* type 리터럴로 함수 타입을 지정
type Add1 = (x: number, y: number) => number;
let myFunc6: Add1 = (x, y) => {
   return x + y;
};

 

//* 인터페이스로 함수 타입을 지정
interface Add2 {
   (x: number, y: number): number;
}
let myFunc7: Add2 = (x, y) => {
   return x + y;
};

 

 

 


 

Ⅱ. TS의 매개변수 표현.


   ☆ TS에서는 함수의 인자를 모두 필수 값으로 간주합니다.

 

           = > 함수의 매개변수를 설정하면,

                  심지어 인자값이 undefined나 null 같은 쓸모없는 값이라 할지라도, 인자로 넘겨야하며,

                  컴파일러에서는 정의한 매개변수 값이 제대로 넘어왔는지 확인합니다.

 

function sum(a: number, b: number): number {
  return a + b;
}
sum(10, 20); // 30
sum(10, 20, 30); // error, too many parameters

 

 

 

 

       Ⅱ - ⅰ. 선택적 매개변수.

              ** 만약에,  순수한 JS를 사용할 때처럼, 유연하게

                      정의된 매개변수의 개수와 정확히 일치하는 만큼 인자를 넘기지 않아도 되게 만들고 싶다면,

                   선택적(optional) 키워드인 물음표(?)를 활용해서 아래와 같이 정의 가능합니다.

 

 

              ex) ? 키워드를 사용해, 'b' 를 선택적 매개변수로 지정.

                        (b가 받을 인수가 없어도 에러가 발생하지 않습니다)

function sum(a: number, b?: number): number {
  return a + b;
}
sum(10, 20); // 30
sum(10); // 타입 에러 없음

 

 

            ≡   ? 키워드 사용은 유니온 타입 ( | undefined ) 을 추가하는 것과 같다고 볼 수 있습니다.

function sum(a: number, b: number | undefined): number {
  return a + b;
}
sum(10, 20); // 30
sum(10); // 타입 에러 없음

 

    

    ++ Null 병합 연산(??) 사용하여서, null 또는 undefined인 경우  '0'을 반환하도록 지정하는 식으로도 처리 가능.

function add(a: number, b?: number, c?: number): number {
   return a + (b ?? 0) + (c ?? 0);
}

add(1, 2, 3); // 6
add(1, 2); // 3
add(1); // 1

 

 

◎ 단,  '선택적 매개변수'를 사용할 때 주의할점은

          선택적 매개변수가 이외의 함수 인자 앞단에 위치하면 안된다는 것입니다. 

         [ 선택적 매개변수는 무조건 뒤로 위치 !]

 

function sum(b?: number, a: number): number {
   return a + (b ?? 0);
}

 

 

       Ⅱ - ⅱ.  매개변수 초기화.

 

             ○ 매개변수 초기화는 JS의 ES6문법과 동일합니다.

 

             ○ 기본값을 할당한, 매개변수의 함수 타입은

                  "옵셔널 파라미터(선택적 매개변수)" 가 적용된 것을 확인 가능합니다.

                    ≒ 매개변수에 기본 값이 있으면, 매개변수에 값을 할당하지 않아도 된다는 의미.

 

              ● 기본 값이 있으면, 굳이 인자 타입을 선언해주지 않아도 됩니다  == "TS의 타입추론"

                   

function sum(a: number, b = 100): number {
// 매개변수 기본 값이 있으면 굳이 인자 타입을 선언하지 않아도 된다 (타입 추론)
   return a + b;
 }
 sum(10, undefined); // 110
 sum(10); // 110
 sum(10, 10) // 20

b의 타입을 추론한 모습

 

 

       Ⅱ - ⅲ.  나머지(rest) 매개변수.

          ※ JS에서 사용되는 '스프레드 매개변수'  역시  직접 타입만 잘 지정하면 TS에서도 문제없이 사용 가능합니다.

function sum(a: number, ...nums: number[]): number {
  const totalOfNums = 0;
  for (let key in nums) {
    totalOfNums += nums[key];
  }
  return a + totalOfNums;
}

 

   ☆다만, !

          TS에서 strict 모드를 true로 하고 사용하기 때문에

          JS의 'arguments 예약어'는 사용될 수 없다는 점을 유의!

 

 

       Ⅱ - ⅳ.  네임드 파라미터.

               ◎ 'named parameters'는 함수 아규먼트 부분 전체를 객체로 감싸주고, 그 뒤에 타입을 정의해주는 방식.

function getText({ name, age = 15, language }: { name: string; age?: number; language?: string }): string {
   const nameText = name.substr(0, 10);
   const ageText = age >= 35 ? 'senior' : 'junior';
   return `name: ${nameText}, age: ${ageText}, language: ${language}`;
}

getText({ name: '홍길동', age: 11, language: 'kor' });
getText({ name: '홍길동' });

 

              ☆ 네임드 파라미터는 함수의 argument 갯수가 많을 때 유용하게 사용가능합니다.

                    :: 아규먼트의 타입 정보들을 뒤로 위치시킴으로서,  한 눈에 함수 아규먼트 구성을 볼 수 있기 때문.

 

 

 


 

 

Ⅲ. TS의 콜백 / 중첩 / 고차 함수.


 

 

Ⅲ - ⅰ 콜백 함수.

           :: 콜백 인자의 타입을 정해줄 때는,

                   위에서 언급했던 call signiture(함수 타입)으로 지정해주면 됩니다.

 

const logging = function (s: string) {
   console.log(s);
};

const init = (callback: (arg: string) => void) => {
   console.log('callback start');
   callback('yes!');
   console.log('callback end');
};

init(logging);
/*
callback start
yes!
callback end
*/

 

 

 

Ⅲ - ⅱ  중첩 함수.

       ::  함수 타입 선언만 잘 해놓으면 간단히 중첩해서 사용이 가능합니다.

 

const calc = (value: number, cb: (arg: number) => void) => {

   const add = (a: number, b: number) => a + b; // 화살표 함수

   function mul(a: number, b: number) { // 함수 표현식
      return a * b;
   }

   let result = mul(add(3, 4), value);
   cb(result);
};

calc(2, (output) => console.log(output)); // 14

 

 

Ⅲ - ⅲ   고차 함수.

         :: 고차 함수(high order function) ==  "함수를 반환하는 함수"

 

const add = (a: number) => {
   return (b: number) => {
      return a + b;
   };
};

// 곧바로 실행
console.log(add(3)(8)); // 11

// 한 번 걸쳤다가 실행
const first = add(3);
console.log(first(8)); // 11

 

 


 

Ⅲ. TS의 this 표현.


 

        ☆ 함수를 다루는데 있어서 가장 중요한 내용 중 하나가 바로  "this" 키워드 입니다.

 

 

     Ⅳ - ⅰ   명시적 this.

interface Cat {
   name: string;
}

const cat: Cat = {
   name: 'Lucy',
};

function someFn(greeting: string) {
   console.log(`${greeting} ${this.name}`); // Error - 'this'에는 형식 주석이 없으므로 암시적으로 'any' 형식이 포함됩니다.
}
someFn.call(cat, 'Hello'); // 위에 에러가 나서 실행이 안됨

           => someFN 메소드는 전역 렉시컬 스포크에 위치하기에,  this에 any 오류가 나타나게 됩니다.

 

     ++ 이 경우, this 타입을 명시적으로(explicitly) 선언 가능합니다.

               == someFn 이라는 메소드의 this의 타입은 명시적으로 ICat 인터페이스를 가리키게 함으로써

                        타입을 명시해 오류를 없앨 수 있습니다.

                   =>> 가짜 매개변수로 this를 선언하면 됩니다.

interface ICat {
  name: string
}

const cat: ICat = {
  name: 'Lucy'
};

function someFn(this: ICat, greeting: string) {
  console.log(`${greeting} ${this.name}`); // ok
}
someFn.call(cat, 'Hello'); // Hello Lucy

 

 


Ⅴ. TS의 함수 오버로딩


 

    ◎ "오버로딩" 이란,  Java등의 언어에서는 매개변수는 다르지만, 내역은 동일한 함수를 말하는 것입니다.

 

    ◎ TS의 함수-오버로드(OVerloads) 역시 이름은 같지만,

            정확히 말하자면 매개변수 타입과 반환 타입이 다른 여러 함수를 가질 수 있는 것을 말합니다.

 

    ◎ TS의 함수-오버로드(OVerloads) 선언법은 중괄호{} 없는 함수를 실제 함수 위에다가 사용해주면 됩니다.

 

function add(a: string, b: string): string; // 오버로드 함수 선언
function add(a: number, b: number): number; // 오버로드 함수 선언
function add(a: any, b: any): any { // 오버로드 함수 실행부 (any를 써준다)
  return a + b;
}

add('hello ', 'world~');
add(1, 2);

 

 

§ 오버로드 함수에서의 any 표현은 TS에서 허용됩니다.

        위 코드를 보면, 함수 실행부에서의 인수와 리턴 타입에 any를 사용했는데,

              컴파일러는 오버로드 함수 선언부의 타입들만 보고 함수를 판단하기 때문에 

              실행부에 any를 사용하는게 문제가 되지 않습니다.