JS로 작성한 React 프로젝트를 TS로 바꾸며 느낀 점 1

아무래도 시리즈물이 될 것 같아서 제목 뒤에 1을 붙였다. 처음엔 그저 두렵기만 했던 타입스크립트.

이젠 타입스크립트 없이 살 수 없는 몸이 되어버렸다. 다음 프로젝트에도 사용하고 싶은 의향 200%




타입 스크립트를 적용하기 전, 멘토님이나 먼저 타입스크립트 맛을 본 동기분들이

타입스크립트로 하면 일단 에러때문에 화면 띄우기가 힘들다…라는 말을 들었고,

나는 에이 뭐 그래봤자 얼마나 심하겠어~ 싶었다… ts의 쓴맛을 보지 못했던 바보같은 나…

기존의 React 프로젝트에 타입스크립트 적용하기

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

# or

yarn add typescript @types/node @types/react @types/react-dom @types/jest

위 명령어를 입력해주면 된다!! 출처


package들 typescript 버전으로 다시 다운받기…

일단 위처럼 하고 나면 엄청난 에러가 날것이다. 우리가 프로젝트에 추가했던 라이브러리들의 typescript 지원 버전을 받아야 한다.

react router dom, redux 부터 시작해서 lodash나 rechart까지…

yarn 공홈에 검색하면 다 나온다.

앞에 @types라고 붙은 것들이 있는데. 그게 바로 그것이다!!

그런데 타입스크립트를 지원해주지 않는 라이브러리도 있더라… 듣고있나요 colortheif..? 빨리 해주세요…ㅠㅠ


typescript로 React component 작성

그리고 작성했던 컴포넌트들에 type을 추가해주어야 한다.

확장자도 jsx에서 전부 tsx로 바꿔주었다.

import React from 'react';

function App(props) { // props : any로 수정하면 에러 안남!
  return (
    <div>
      hello, world!
    </div>
  );
}

export default App;

타입스크립트에서는 이런 최고로 간단한 형태의 컴포넌트조차 컴파일에러가 난다.

props의 타입을 지정해주지 않아서 생기는 에러이다.

딱히 받아오는 props가 없을 때에, 일단 props : any로 지정해주면 컴파일에러는 피할 수 있다.

사실 뭐든간에 any로 지정해준다면 에러는 피할 수 있겠지만… 그러면 typescript를 활용하는 의미가 없다고 생각한다.

서드파티 라이브러리를 사용한다거나 할때는 불가피하게 any를 사용해줘야 할 수도 있지만… 최대한 any의 사용은 지양하려고 한다.

만약 해당컴포넌트가 받아올 props가 존재할 경우에는 이와 같이 구조분해할당 및 타입 할당을 해줄 수 있다.

function Parent(props : any){
  return <App description='hello, world!' /> //App으로 description props를 보냄
}

...

function App({description}: {description : string}) { //string type으로 명시
  return (
    <div>
      {description}
    </div>
  );
}

보다 복잡한 형태의 props를 보내게 될 경우에는 interface나 type을 활용할 수 있다.

type과 interface의 차이로는 type으로 했을 경우에는 자동완성이나 마우스를 올려다 댔을 때 타입이 조금 더 명확하게 나타나고

interface는 extends 키워드를 사용하여 확장이 가능하다.

지금 진행중인 프로젝트에서는 interface로 통일해서 사용중이다!

interface TNewBranch {
  new_address: string;
  brand: {
    id: number;
    name: string;
    sub_category: {
      id: number;
      name: string;
    };
  };
}

function RecruitCard({ newbranch }: { newbranch: TNewBranch }) {
  return (
    <div>
      {...}
    </div>
  );
}

props를 넘겨주다보면 ref나, setState함수나, component들을 넘겨줘야할 때도 있을텐데

타입을 대체 뭘로 써줘야하는 지 모르겠을 때가 있다…일단 나는 그랬다…ㅎㅎ..

그럴 때는 vscode를 믿고 마우스를 가져다 대 보자.

짜잔! 타입이 나타난다. 이것 또한 typescript의 장점이라 할 수 있겠다.

interface TFilterModal {
  rangeState: [number, number];
  setRangeState: React.Dispatch<React.SetStateAction<[number, number]>>;
  buttonRef: null | React.MutableRefObject<null>;
  setModalOn: React.Dispatch<React.SetStateAction<boolean>>;
  mainText: string;
  subText: string;
  marks: { [k: number]: string };
}

function FilterModal({ rangeState, setRangeState, buttonRef, setModalOn, mainText, subText, marks }: TFilterModal) {

  return (
    <>
    ...
    </>
  );
}

이런식으로도 props를 받아올 수 있게 된다. 타입스크립트 어메이징~~


변수를 객체의 key값으로 사용하고 싶을 때

코드를 짜다 보니 객체의 특정 key값의 value로 같은 일을 하는 함수가 반복적으로 필요하게 되어서,

동적으로 key값을 받아서 결과를 리턴하는 함수를 만들었는데, 이와 같은 에러와 만나게 되었다.

그러니까… string은 객체의 key값으로 사용할 수 없다는 뜻이다. 해결법으로는 두가지가 있다.

  1. interface에 위처럼 해주면 key값으로 string을 사용할 수 있게 된다.

참고자료 typescript 핸드북 의 indexable types 항목

  1. as keyof typeof로 접근
val.brand_info[key as keyof typeof val.brand_info]

Written by@Mengkki
common fangirl

GitHub