[Typescript pair study] 기초 타입 세션 ① any, never, void, alias, union 등

이민선(Jasmine)·2023년 4월 30일
1

두둥 첫 세션!!

이번 시간에는 아래 순서대로 수민님과 번갈아가며 각자 만들어온 소스코드를 공유하고 타입에 대해 설명 및 질의응답하는 시간을 가졌다.

이수민
1. any
2. array
3. never
4. rest parameter 사용 시 type 지정

이민선
5. object
6. alias
7. union

이수민
8. tuple
9. unknown
10. void

이민선
11. optional parameter 사용 시 type 지정
12. default parameter 사용 시 type 지정

이번 포스팅에서는 페어 스터디를 진행하면서 새로 알게된 것들과 중요했던 type들 위주로 첫 세션을 정리해보려고 한다.

💡 나의 파트

- object type은 권장되지 않는다.

예를 들어 아래와 같은 코드를 보자.

  function getLunchMenu(menus: object): object {
    return menus;
  }
  // 객체도 인자로 전달할 수 있고
  console.log(getLunchMenu({ mainMenu: "rice", subMenu: "kimchi" }));
  // 배열도 인자로 전달 가능하다.
  console.log(getLunchMenu(["rice", "kimchi"]));

getLunchMenu라는 함수와 매개변수인 menus에 각각 object type을 지정해보았다.
자바스크립트에서 object는 배열을 포괄하는 type이기 때문에 인자로 배열을 전달하더라도 아무런 에러가 나지 않는 것을 볼 수 있다.
심지어 인자로 전달하는 객체의 key/value도 사전에 지정된 바가 없으면 아무렇게나 전달 가능하다.
따라서 object 타입을 사용하는 것은 권장되지 않으며, alias나 interface를 사용하여 객체의 key의 type까지 사전에 지정하는 것이 좋다.

예를 들어 myFavoriteMovie라는 객체와 이 객체의 type인 Movie를 지정해보았다. key인 title과 cast의 type까지 명시적으로 지정할 수 있으므로 가독성, 유지보수성 측면에서 object보다 낫다.

  type Movie = {
    title: string;
    cast: string[];
  };

  const myFavoriteMovie: Movie = {
    title: "Gravity",
    cast: ["Sandra Bullock", "George Clooney", "Ed Harris"],
  };

또한 배열의 경우에도 string[], number[][] (2차원 배열) 이런 식으로 배열임을 명확히 알려야 한다.

- typescript에서는 매개변수의 개수와 인자가 일치하지 않을 경우 에러가 발생한다. → optional parameter로 해결

예를 들어 githubRepository라는 함수를 만들어보았다. (우리 페어스터디의 github repo를 생성하다가 영감을 얻었다. ㅋㅋㅋㅋㅋ)

  type Repository = {
    name: string;
    description?: string; // description이 없을 수도 있으므로 type에도 ? 연산자 사용
  };

  function githubRepository(name: string, description?: string): Repository {
    //description이 있을 경우와 없을 경우를 각각 if문으로 나눠야 한다.
    // description이 인자로 전달 되었을 떄
    if (description) {
      return {
        name,
        description,
      };
      // description이 인자로 전달 되지 않았을 떄
    } else {
      return {
        name,
      };
    }
  }
  // description이라는 매개변수에 인자를 전달하지 않아도 오류가 나지 않음.
  console.log(githubRepository("javascript_study"));
  console.log(
    githubRepository("typescript_study", "typescript를 공부하는 스터디입니다.")
  );

github repo를 생성할 때 name은 필수 입력 사항이지만, description은 선택 사항이다.
그렇다고 해서 description이라는 매개변수에 인자를 전달하지 않으면 에러가 난다. (javascript에서는 이 상황에서 에러가 나지 않는 것과 구별된다.)
따라서 typescipt에서 optional parameter가 유용해지는데, 이 때 optional parameter인 description 속성을 type에 포함하고 싶을 때는 동일한 방법으로 ? 연산자를 사용하면 된다.

- default parameter를 설정하고, 각각의 매개변수에 type을 지정할 수도 있다.

default parameter가 사용된 함수인 makeReceipt라는 함수를 만들어보았다. itemToAdd, shoppingList, payment 3가지 매개변수가 있으며, 함수 내부에서 itemToAdd를 shoppingList 배열에 push 하여 shoppingList와 payment 속성을 가진 객체를 return하는 함수이다.

이 때 shoppingList의 default 값으로 빈 배열을, payment의 default 값으로 "credit-card"를 지정해놓았다. 따라서 optional parameter일 때와 달리, "egg"라는 인자 한 개만 전달해도 빈 배열에 "egg"가 push되고 결제 방법으로 credit-card가 지정되어 영수증이 출력된다.

  type PaymentMethod = "credit-card" | "mobile-pay" | "cash";
  type Item = "egg" | "coffee" | "noodle";

  type Receipt = {
    shoppingList: Item[];
    payment: PaymentMethod;
  };

  function makeReceipt(
    itemToAdd: Item,
    // shoppingList라는 매개변수에 인자를 전달하지 않은 경우 default parameter로 빈 배열이 할당된다.
    shoppingList: Item[] = [],
    // payment라는 매개변수에 인자를 전달하지 않은 경우 default parameter로 빈 배열이 할당된다.
    payment: PaymentMethod = "credit-card"
  ): Receipt {
    shoppingList.push(itemToAdd);
    return {
      shoppingList,
      payment,
    };
  }
  console.log(makeReceipt("egg", ["coffee", "noodle"], "mobile-pay"));
  // { shoppingList: ["coffee", "noodle", "egg"], payment: "mobile-pay"}
  
  // shopping list와 payment에 인자를 전달하지 않으면 default parameter로 설정된 값들이 반환된다.
  console.log(makeReceipt("egg"));
  // { shoppingList: ["egg"], payment: "credit-card"}

💡 수민님 파트

- any/unknown 차이

any와 unknown의 차이가 헷갈렸는데 수민님이 정확히 짚어주셨다.

다른 타입의 변수에 any/unknown 타입의 변수를 할당할 수 있는가?

  • any type으로 지정된 변수는 아무 타입의 변수에나 할당이 가능하다.
    // any 타입의 변수 선언
    const variable: any;

    // 어떤 타입의 변수에도 할당 가능
    let anyType: any = variable; // 가능
    let booleanType: boolean = variable; // 가능
    let numberType: number = variable; // 가능
    let stringType: string = variable; // 가능
    let objectType: object = variable; // 가능
  • 반면 unknown type으로 지정된 변수는 다른 타입의 변수에 할당할 수 없다. 다만 any type으로 지정된 변수에만 할당이 가능하다.
    const variable2: unknown;

    let anyType: any = variable2 // 가능
    let booleanType: boolean = variable2  // Error : Type 'unknown' is not assignable to type 'boolean'
    let numberType: number = variable2 //  Error : Type 'unknown' is not assignable to type 'number'
    let stringType: string = variable2 //  Error : Type 'unknown' is not assignable to type 'string'
    let objectType: object = variable2 //  Error : Type 'unknown' is not assignable to type 'object'

- type을 지정해주지 않으면 암시적으로 any type이 지정된다.

    // 암시적으로 any 타입 지정
    let color2;
    color2 = 12;
    color2 = 'rainbow';

물론 any 타입은 타입스크립트의 이점(코드 안정성, 가독성, 생산성 등)을 활용하지 못하는 타입이기 때문에 가능한 한 사용하지 않는 것이 좋다.

- void/never 차이

둘 다 값을 반환하지 않는 함수일 경우 사용하지만, 값 반환 가능성과 코드의 의도에 따라 사용되는 경우가 다르다.

예를 들어 void의 경우 함수가 값을 반환하지 않겠다는 의도를 명시적으로 나타내기 위해 사용한다.

function addNum(num :number) :void { 
   return num * 2  // 에러 발생
} 

console.log만 있고 return 값은 없는 함수에 많이 사용한다.

function printMessage(message: string): void {
  console.log(message);
}

반면 never의 경우에는 함수가 항상 예외를 던지거나 무한루프에 빠지는 경우를 나타내기 위해 사용된다.

 //오류 출력
function invalid(message:string): never {
   throw new Error(message);
}

 //무한 루프
function infiniteAnimate(): never {
   while ( true ) {}
}

굳이 의도로 구분하여 설명하자면 안 하고(void)/못 하고(never)의 차이 정도로 구분해볼 수 있겠다.

여기까지 첫 세션에서 다룬 내용들 중 중요한 것들을 추려봤다. 수민님과 함께 열심히 준비해와서 성공적 마무리였다!! 👏🏻👏🏻👏🏻👏🏻👏🏻
직접 소스코드를 만들어보며 특정 타입이 적용될만한 찰떡 같은 케이스들을 떠올려보며 실력을 향상하고 기초 타입 복습이 되는 것도 좋지만, 서로 생각지 못했던 부분을 공유하여 지식이 확장되는 점도 아주 좋았다.

다음 시간에는 interface, enum, type inference, type assertion에 대해 함께 공부할 것이다.

📢 수민님 수고 많으셨습니다~~!! 😄😄😄 다음주도 화이팅!!

github 링크
https://github.com/minsun0714/Typescript_pair_study/tree/main/basic-type

profile
기록에 진심인 개발자 🌿

0개의 댓글