이번에 올리게 될 개발 튜토리얼 시리즈에서는 리액트 프로젝트에서 타입스크립트를 사용하는 방법에 대하여 알아보겠습니다.

JavaScript 는 Weakly-typed 된 언어이기 때문에 특정 숫자 변수를 선언 한 다음에 그 안에 다른 타입의 값을 담을 수 있어요. 예를 들자면, 숫자로 선언한 변수에 문자열을 넣을 수도 있고, null을 넣을 수도 있고 배열을 넣을 수도 있고 객체를 넣을 수도 있죠.

let value = 5;
value = '안녕하세요';
value = [1, 2, 3, 4, 5];
value = null;

이로 인하여 우리가 실수를 저지를 확률이 생기게 되버리죠. 예를 들어서 배열인줄 알고 특정 값의 배열 내장 함수를 사용하려고 했는데 알고보니 null 이여서 앱이 크래쉬가 뜬다던지.. 숫자인줄 알고 비교했는데 알고보니 문자열이였다던지..

추가적으로, JavaScript를 사용 할 땐 IDE 지원이 좀 부족합니다. 작동하지 않습니다. 아마 C++, Java, C# 등의 언어를 사용하신 경험이 있으시다면 JavaScript IDE 에서 지원하는 자동완성 시스템이나 오류 확인 시스템에 은근히 불만이 있을거예요.

JavaScript 의 불편함

자동완성이 구리다.

예를 들자면, VS Code 를 사용 할 때 이 정도의 자동완성은 됩니다.

image.png

그런데 배열을 파라미터로 값으로 받아오는 함수를 만들게 될 때 해당 함수 내부에서는 자동완성이 안됩니다.

image.png

함수 파라미터 타입 체킹 안해준다.

아니면.. 문자열을 가지고 어떤 처리를 하는 함수를 만들었다고 가정해봅시다.

function getLength(str) {
  return str.length;
}

그런데 해당 함수를 다음과 같이 숫자를 넣어서 호출해도 전혀 문제가 안됩니다.

getLength(3);

다른 언어였으면 파라미터 타입이 이상하다면서 오류를 냈을텐데 말이죠, 자바스크립트 환경에서는 실행해볼때까지 해당 코드에 오류가 있는지 없는지 알 방법이 없습니다.

리덕스 쓸 때 불편하다.

리액트를 사용하는 경우 실무에서 실제로 겪을 수 있는 불편함 중에서는 다음과 같은 상황이 있습니다. 예를 들어서 여러분들이 리덕스를 사용해서, useSelector 를 통해 리덕스 스토어 안에 들어있는 상태를 조회한다고 가정을 해봅시다.

image.png

그럼 상태 안에 어떤 값이 들어있는지 에디터 단에서 모르기 때문에, Redux DevTools 를 한번 확인해보거나, 리듀서 관련 코드가 들어있는 파일을 열어서 그 안에 어떤 상태가 들어있더라..! 하고 열어보아야 한다는 귀찮음이 있습니다.

리액트 컴포넌트 쓸 때 어떤 props 를 넣어야하는지 에디터에서 알 방법이 없다.

리액트 컴포넌트에서는 propTypes 라는 것을 사용하면 특정 컴포넌트에서 필요한 props 를 지정해서 컴포넌트에서 필요한 props 가 없다면 콘솔에 경고를 출력하도록 할 수 있습니다.

그런데요, propTypes 쓰는거 솔직히 너무 귀찮습니다. 특히 props 로 배열이나 객체 가져와야 하는경우엔 무슨 arrayOf, shape 이런거 써야 되고 여러 타입인 경우엔 oneOfType 란걸 써야 하는데 솔직히 너무 안외워지고 불편합니다.

그리고, propTypes 를 설정해도 props 빠뜨리면 브라우저 단에서만 경고를 보여줄 뿐 에디터에서는 아무 경고도 보여주지 않기 때문에 실제로 코드를 실행해봐야만 우리가 실수를 했는지 안했는지 알 수가 있다는게 참 불편합니다.

처음엔 불편한지 모른다

이렇게 끝도 없이 JavaScript 의 불편함에 대해서 계속해서 나열 할 수 있습니다. 하지만 아마 대부분 처음엔 불편한지 모릅니다. 저도 마찬가지예요. 처음엔 불편한지 몰랐어요. TypeScript 를 사용해본 분이라면 불편함을 심하게 느낄 겁니다. TypeScript를 경험해본 정말 많은 개발자분들은 다들 "TypeScript 없이 어떻게 개발을 하지?" 라는 생각을 하게 됩니다.

한번 써보면, 얼마나 불편한지 깨달을 수 있습니다. 그리고 정말, 여러분의 개발 생산성을 매우 향상시켜줄거예요. 특히 리액트 프로젝트에서 타입스크립트 쓰면 진짜 개발 편해집니다.

써야 하는 이유

써야 하는 이유: "정말 좋다." 이 한마디로 다 설명 되지만 제가 생각하기에 3가지 가장 큰 강점들을 나열해보자면 다음과 같은 큰 장점이 있습니다.

  1. IDE 를 더욱 적극적으로 활용 할 수 있습니다.
    자동완성 및 타입 체킹이 되기 떄문에 개발 생산성이 정말 높아집니다. 어떤 컴포넌트를 사용하거나, 함수를 사용 할 때 해당 파일을 직접 얼여보지 않고도 어떤 props 또는 파라미터를 넣어줘야 하는지 알 수 있습니다. 리덕스를 사용하게 될 때에도, 리듀서 관련 코드를 열지 않고도 상태 객체가 어떤 구조로 이루어졌는지 확인 할 수 있죠

  2. 바보같은 실수, 줄일 수 있다.
    때로는, 우리는 바보같은 실수를 합니다. 아 왜 내가 이런 실수를 했지! 하며.. 에를 들어서 함수에 타입을 잘못 설정했다던지, 이상한 오타를 냈다던지, 다른 타입끼리 비교를 했다던지.. null 체킹을 빠뜨렸다던지.. TypeScript 를 사용하면 이런 실수들을 코드를 실행해보기 전에도 에디터 단에서 바로 알 수 있기 때문에 실수를 많이 줄일 수 있답니다.

  3. 협업 할 때 유용하다
    결국 위에 언급했던 1번의 연장선입니다. IDE에서 컴포넌트, 함수 등을 사용 할 때 어떤 값을 어떤 타입으로 넣어야 하는지 바로 IDE상에서 확인 할 수 있기 때문에 굳이 주석으로 작성하거나, 코드를 읽어보거나, 협업하는 사람에게 물어보지 않아도 쉽게 사용 할 수 있습니다.

앞으로 이 시리즈에서 다룰 내용

이 시리즈를 진행하기 전에, TypeScript를 이미 잘 알고있다면 참 좋겠지만, 그렇지 않은 독자분들께서도 쉽게 타입스크립트에 입문하고 리액트 프로젝트에 적용 할 수 있도록 리액트에서 TypeScript를 활용하기 위해 핊요한 기본기를 가볍게 다룹니다. 이 튜토리얼에서는 모든 기능을 세세하게 다루진 않기 때문에 TypeScript를 꼼꼼하게 배워보고 싶다면 다음 링크를 참고해보세요.

먼저 타입스크립트의 기본기를 배우고 난 다음에는 타입스크립트가 적용된 리액트 프로젝트를 만들고, 컴포넌트를 작성 할 때 타입스크립트로 작성하는 방법에 대해서 다뤄보게 됩니다.

이 튜토리얼에서는 클래스형 컴포넌트를 타입스크립트를 작성하는 것에 대해서 다루지 않습니다. 따라서, 나중에 클래스 컴포넌트를 작성하는 방법을 알아보시려면 이 링크를 참고하세요. 클래스 컴포넌트를 다루지 않는 이유는 앞으로 여러분도, 저도 클래스 컴포넌트를 사용 할 일이 별로 없을거라고 생각하기 때문이고 글을 쓰는 것 또한 불필요한 리소스라고 생각하기 때문입니다.

이 튜토리얼에서는 함수형 컴포넌트와, Hooks 를 사용하는 것에 집중합니다. 따라서, 우리는 TypeScript 환경에서 useState 또는 useReducer 를 사용하여 상태관리를 하는 방법을 배우겠습니다.

추가적으로, 글로벌 상태관리를 할 때를 대비하여 Context API를 활용하는 방법도 빠질 수 없죠. 효율적으로 TypeScript와 Context API 를 사용하는 방법 또한 다뤄보게 됩니다.

그리고 리덕스를 다루는 방법도 배워 볼 것이구요, typesafe-actions 라는 라이브러리를 사용하여 정말 깔끔하게 액션 생성함수와 리듀서를 작성하는 방법도 배워볼겁니다. 그리고, 제가 요즘 좋아하는 리덕스 모듈의 디렉터리 구조도 소개시켜드릴게요.

마지막으로, 리덕스 미들웨어를 사용하는 방법도 다뤄볼것입니다. 이 때 우리는 redux-thunk 와 redux-saga 를 사용해보게 됩니다.