타입 스크립트 에서 Vue 컴포넌트 를 개발 하 는 방법 | TOAST UI : : Make Your Web Delicious ! 
 내 가 처음 SPA 프로젝트 를 진행 했 던 때 는 2012 년 이 다 . 그때 제일 핫 했 던 백본 ( Backbone ) 을 기반 으로 구축 한 꽤 큰 규모 의 프로젝트 였 다 . 그때 는 지금 처럼 프론트엔드 개발 환경 이 좋 지 않 았 고 SPA 라는 개념 자체 가 겨우 슬슬 알려 지 기 시작 한 시기 였 다 . MVC 에서 벗어나 질 못한 프레임 웍 들 이 주 를 이루 었 던 프론트엔드 진영 이 었 다 . 앵 귤 러 JS ( AngularJS ) 가 MVC 가 맞 느니 아니 니 박 터지 는 가운데 리 액트 ( React ) 라는 아종 이 등장 했 다 . 리 액티브 와 함수 형 패러다임 의 영향 을 받 은 이 프레임 웍 은 빠르 게 성장 했 다 . 그걸 이끈 개발자 들 이 나 보다 나이 가 어려서 배 가 아프 다 . 그리고 엄청난 생략 이 지만 Vue 가 나왔 다 . Vue 는 여러 가지 프레임 웍 에서 영향 을 받 았 다 . 코드 의 모습 은 리 액트 와 비슷 했 지만 스테이트 측면 에서 리 액티브 를 적극 적 으로 활용 했 다 . Vue 는 사용 하 기 편하 다는 이유로 리 액트 에 버금가 는 인기 의 프레임 웍 으로 성장 하 게 된다 . 리 액트 와 리덕 스 는 웹 개발자 들 이 그 근간 인 불변성 ( Immutable ) 을 이해 했 다 쳐도 막상 실무 에 적용 할 때 걸림돌 이 많 았 을 것 이 다 . Vue 의 사용 율 은 날 이 갈수록 증가 하 고 있 다 . 
 프론트엔드 진영 의 갈증 은 자바 스크립트 의 언어 적 인 단점 을 극복 하 기 에 이른다 . 커피 스크립트 , 플로우 ( Flow ) , 바벨 ( Babel ) , 그리고 MS 의 타입 스크립트 가 바로 그러 한 노력 이 다 . 물론 바벨 은 표준 스펙 의 호환 성 을 높이 는 도구 이 기 때문 에 언어 자체 를 독자 적 으로 개선 한 경우 에 해당 하 지 않 아 성격 이 다르 다고 볼 수 있 다 . 아무튼 초창기 이 분야 를 이끌 던 커피 스크립트 는 몇 가지 걸출 한 컨셉 을 ES 6 에 물려주 는 위대 한 성과 를 남기 고 화려 하 게 은퇴 하 는 중 이 다 . 플로우 와 타입 스크립트 는 자바 스크립트 ( ECMAScript ) 슈퍼 셋 으로 기존 의 문법 위 에 엄격 한 타입 을 적용 하 려 했 다 . 런타임 만 존재 하 는 인터프리터 언어 에 컴파일 타임 에 해당 하 는 검증 단계 를 도입 했 다 . 플로우 와 타입 스크립트 의 보이 지 않 는 치열 한 싸움 에서 는 결국 타입 스크립트 가 승리 했 고 트랜스 파일 언어 로 는 타입 스크립트 가 독보 적 인 존재 가 되 었 다 . 
 엄격 한 타입 에 대해서 는 개인 적 으로 긍정 적 인 견해 를 갖 고 있 지 않 다 . 하지만 다 형성 을 위한 프로토콜 혹은 인터페이스 수준 의 명시 적 인 모듈 시그 니 처 는 분명 도움 된다고 생각 한다 . 호불호 가 있 지만 요즘 자바 스크립트 라는 괴이 했 던 언어 는 점점 준수 한 언어 로 발전 하 고 있 다 . 이 언어 에 타입 이 없 는 것 까지 비판 한다면 칭찬 할 만 한 구석 은 정말 이 지 하나 도 없 는 언어 일 것 이 다 . 뭐 든 되 지만 이 도 저 도 아니 고 바로 그 점 이 이 언어 의 장점 이 라고 생각 한다 . 타입 스크립트 가 대세 가 될지 혹은 또 다른 커피 스크립트 가 될지 나 는 모르 겠 다 . 다만 프론트엔드 를 개발 하 는 입장 에서 타입 스크립트 에 대한 관심 과 기본 적 인 학습 은 필요 하 다고 생각 했 다 . 그래서 초창기 에 시간 을 투자 해 어느 정도 학습 해 두 었 다 . 언어 의 이해 와 개념 이 얼추 잡힌 상태 에 도 타입 스크립트 에 그리 호의 적 이 진 않 았 고 특별히 실무 에 사용 할 생각 도 없 었 다 . 
 처음 타입 스크립트 를 학습 하 고 시간 이 몇 년 즈음 흘러 내 머릿속 에서 지워질 무렵 타입 스크립트 에 대한 관심 이 높 아 지 고 있 었 다 . 심지어 사내 에서 는 프론트 개발자 가 아닌 개발자 들 에 의해 실무 에 적용 되 는 케이스 가 많 아 졌 다 . 그만큼 타입 스크립트 의 영역 이 더 커진 것 이 다 . 엄격 한 타입 의 언어 를 다루 던 개발자 들 이 자바 스크립트 를 다뤄야 할 때 그 중간 의 완충 역할 로 타입 스크립트 를 선택 했 다 . 타입 을 사용 한다는 건 단순 하 게 문법 을 쓰 고 안 쓰 고 의 문제 가 아닌 어플리케이션 설계 전체 에 영향 을 주 는 문제기 에 충분히 공감 이 갔 다 . 사내 의 요청 도 있 었 지만 팀 내 에서 도 타입 스크립트 에 대한 전문 성 이 필요 한 상황 이 었 다 . 그래서 당시 프로토타입 으로 개발 중 이 던 프로젝트 의 정식 버전 은 타입 스크립트 를 사용 하 는 것 으로 결정 했 다 . 그 프로젝트 는 타입 스크립트 와 동일 한 이유 로 Vue 프레임 웍 을 사용 했 다 . 
 Vue 진영 은 현재 개발 중 인 3 . 0 의 코드 베이스 를 모두 타입 스크립트 로 변경 할 정도 로 타입 스크립트 에 호의 적 이 다 . 아직 2 . x 대 의 버전 이 지만 그래도 Vue 와 타입 스크립트 는 잘 어울릴 것 으로 예상 했 다 . 프로젝트 에서 의 첫 고민 은 오브젝트 기반 의 컴포넌트 와 클래스 기반 의 컴포넌트 선택 이 었 다 . 초반 의 경험 으로 는 선택 할 수 없 다고 판단 하 고 제일 밑 베이스 컴포넌트 에 해당 하 는 컴포넌트 는 오브젝트 기반 으로 그 외 나머지 는 클래스 기반 컴포넌트 로 진행 하 기 로 했 다 . 베이스 컴포넌트 들 의 개수 가 더 적 었 다 . 결국 클래스 기반 의 컴포넌트 로 가 지 않 을까 하 는 추측 에서 였 다 . 진행 과정 에서 알 게 되 었 지만 결정 에 는 Vuex 도 한몫 을 하 고 있 었 다 . 이 글 은 선택 에 대한 경험 과 전반 적 인 결과 를 공유 하 고자 작성 했 다 . 
 자바 스크립트 와 Vue 컴포넌트 
 서론 이 길 었 다 . 이렇게 서론 이 길 었 던 핑계 를 대 자면 격세지감 을 느껴서 다 . 지금 내 가 만드 는 코드 들 은 SFC 라는 브라우저 는 이해 할 수 없 는 구조 의 파일 에 담겨 있 고 심지어 언어 도 자바 스크립트 가 아니 다 . 브라우저 에서 디버깅 할 때 보이 는 코드 들 은 브라우저 가 실제로 사용 하 는 코드 가 아니 고 소스 맵 이 재 구성 한 유령 같 은 코드 다 . 이렇게 된 것 도 오래 전 일 이 라 특별 할 것 도 없 지만 격세지감 을 느낀다 . 사실 프론트엔드 에서 격세지감 을 느끼 는 것 도 새삼 스럽 다 . 
 SFC ( Single File Component ) 는 Vue 가 권장 하 는 Vue 컴포넌트 전용 파일 포맷 이 다 . 한 파일 안 에 템플 릿 과 자바 스크립트 그리고 CSS 까지 정의 한다 . Vue 는 개발자 가 컴포넌트 를 개발 할 때 클래스 를 정의 하 기 보다 는 클 래스 를 만들 수 있 는 옵션 을 정의 하 는 형태 로 개발 한다 . 
 todos : [' TASK 1 '], 
 간단 한 Todolist 컴포넌트 를 구현 했 다 . Todo 목록 을 가지 고 있 는 데이터 는 todos 라는 배열 이 다 . 배열 안 에 string 타입 으로 할 일 을 저장 한다 . 템플 릿 에서 는 todos 를 순회 하 며 li 엘리먼트 로 Todolist 를 그린다 . 인풋 박스 에 새로 할 일 을 입력 하 고 엔터 를 치 면 todos 배열 을 업데이트 한다 . 단순 한 기능 의 컴포넌트 고 제대로 동작 한다 . 이제 여기 에 타입 스크립트 를 적용 해 보 자 . 
 타입 스크립트 를 Vue 컴포넌트 에 적용 하 는 방법 에 는 두 가지 방법 이 있 다 . Vue . extend 를 이용 해 객체 로 만드 는 방법 과 Class 로 만드 는 방법 이 있 다 . 현재 진행 하 고 있 는 프로젝트 에서 는 장단 을 비교 해 볼 목적 으로 컴포넌트 성격 에 따라 구분 을 지 어 둘 다 사용 해 봤 다 . Vue . extend 를 이용 하 는 방법 을 먼저 다룬다 . Vue . extend 를 이용 해서 컴포넌트 를 정의 하 는 방법 은 타입 스크립트 를 사용 하 지 않 았 을 때 의 컴포넌트 와 거의 비슷 하 다 . 
 자바 스크립트 에서 의 Vue 컴포넌트 정의 방법 과 동일 하 게 컴포넌트 생성 옵션 객체 로 컴포넌트 를 정의 한다 . 다만 타입 이 선언 된 Vue . extend 를 사용 하 게 되 어 타입 의 도움 을 받 을 수 있 다 . vscode 에서 는 extend 위 에 마우스 오버 하 는 것 으로 간단 하 게 타입 정보 를 볼 수 있 고 Peek Definition 으로 아래 이미지 와 같이 extend 가 어떤 시그 니 처 를 가질 수 있 는지 모두 확인 할 수 있 다 . 
 Vue 프로젝트 @ type 디렉 토리 에 정의 된 타입 선언 에 의해 extend 를 사용 하 면 컴포넌트 를 개발 할 때 타입 스크립트 의 도움 을 받 게 된다 . 허용 되 지 않 은 컴포넌트 옵션 에 는 경고 와 API 나 컴포넌트 멤버 의 잘못 된 사용 에 대한 경고 역시 정상 적 으로 동작 한다 . 그리고 데이터 도 정상 적 으로 타입 이 추론 된다 . 초반 에 이 정도 의 테스트 를 할 때 는 매우 행복 하 게 진행 했 다 . 하지만 곧 큰 문제 를 발견 하 게 된다 . 
 컴포넌트 데이터 로 사용 할 Todo 타입 을 선언 했 다 . Todo 타입 의 데이터 를 부모 컴포넌트 에 서 프 롭 으로 전달 받 을 목적 으로 컴포넌트 에서 프로 퍼티 를 정의 할 때 type 으로 Todo 타입 을 사용 할 수 있 을 것 으로 기대 했 다 . 아무 의심 없이 배열 의 제너릭 타입 Todo 를 사용 한다는 의미 로 Todo [ ] 을 사용 했 다 . 
 type : Todo [ ] , 
 하지만 이런 코드 는 곧 에러 를 만나 게 된다 . 
 타입 으로 사용 되 야 하 는 Todo 가 값 으로 사용 되 고 있 다고 에러 를 출력 한다 . 즉 type : Todo [ ] 은 타입 을 선언 한 것 이 아니 고 type 에 Todo [ ] 라는 값 을 할당 한 것 이 다 . 생각 해 보 니 문법 적 으로 맞 는 말 이 었 다 . 그리고 타입 스크립트 의 타입 들 은 개발 중 혹은 컴파일 과정 에서 만 도움 을 줄 뿐 실제 트 렌스 파일 된 자바 스크립트 코드 에서 는 남 아 있 지 않 기 때문 에 값 으로 는 사용 할 수 없 다 . 자바 스크립트 기본 타입 을 사용 했 을 때 는 Number 나 Array 같이 실제 값 으로 쓸 수 있 는 대상 이 있 었 기 에 가능 했 다 . 검색 해 보 면 몇 가지 방법 들 이 논의 되 고 있 는데 아직 은 마음 에 드 는 방법 이 없 다 . 
 ** 타입 스크립트 에서 객체 형태 로 컴포넌트 를 정의 할 때 props 의 타입 으로 타입 스크립트 의 타입 을 사용 할 수 없 다는 이 치명 적 인 단점 은 현재 해답 을 찾 지 못했 다 . ** 진행 중 인 프로젝트 에서 는 말단 베이스 컴포넌트 에 해당 하 는 컴포넌트 들 만 객체 형태 로 컴포넌트 를 정의 하 고 있 는데 이 문제 로 타입 을 사용 하 지 않 고 자바 스크립트 기본 타입 으로 풀 어서 받 는다 . 
 Vuex 를 연동 하 면서 또 다른 문제 에 봉착 했 다 . 이 문제 는 다른 양상 으로 class 기반 컴포넌트 에서 도 발생 한다 . Vuex 의 맵 핑 핼 퍼 는 스토어 에 정의 한 각종 데이터 관련 기능 들 을 간단히 컴포넌트 의 멤버 로 맵 핑 해 준다 . 맵 핑 핼 퍼 는 자바 스크립트 기반 으로 작업 할 때 거의 모든 스토어 의 기능 에 사용 했 다 . 맵 핑 핼 퍼 를 타입 스크립트 에서 사용 하 면 메 서 드 나 데이터 가 모두 String 값 과 기타 맵 핑 핼 퍼 옵션 으로 세탁 되 어 버리 기 때문 에 타입 스크립트 는 해당 멤버 가 컴포넌트 에 존재 한다고 추론 할 수 없 다 . 
 ... mapActions ( [ ' addTodo ']), 
 그래서 맵 핑 핼 퍼 를 사용 하 지 못한다 . 직접 인다 이렉 션 메서 드 를 만들 거나 액션 의 경우 dispatch 를 직접 실행 하 는 방법 으로 스토어 를 통해 접근 해야 한다 . 
 " Vue . extend 는 타입 스크립트 와 좋 은 조합 이 아니 다 " 라는 결론 을 내렸 다 . 
 Vue . extend 와 객체 를 이용 하 는 방법 은 타입 스크립트 와 문제 가 있 기 도 했 지만 타입 스크립트 환경 에서 는 컴포넌트 도 class 로 작성 하 는 게 옳 지 않 을까 하 는 생각 도 있 었 다 . Vue . extend 는 Vue 프레임 웍 에 무게 를 준 방향 이 고 Class 기반 컴포넌트 는 언어 에 무게 를 더 준 방향 이 라고 생각 했 다 . ES 6 에서 도 Class 기반 의 컴포넌트 를 사용 할 수 있 지만 Vue 는 컴포넌트 를 컴포넌트 생성 옵션 객체 로 정의 하 는 방법 을 기반 으로 디자인 되 었 기 때문 에 현재 까진 ES 6 에서 도 객체 형태 가 제일 적합 하 다 . 버전 3 부 터 는 어찌 될지 모르 지만 Vue 가 지향 하 는 바 도 그렇 다고 생각 한다 . 클래스 기반 의 Vue 컴포넌트 는 Vue 커뮤니티 에서 도 옳 은 해답 이 나왔 다기 보다 는 현재 해답 을 찾아가 는 과정 에 있 다 . 아마도 클래스 기반 컴포넌트 는 타입 스크립트 가 아니 었 다면 전혀 고려 하 지 않 았 을 것 이 다 . 
 ... mapActions ( [ ' addTodo ']) 
 클래스 에서 는 get 과 set 으로 computed 를 정의 하 고 메 서 드 는 클래스 메서 드로 직접 사용 되 며 클래스 안 에서 의 데이터 필드 는 그대로 Vue 데이터 로 사용 된다 . 그 외 의 watcher 나 props 와 같 은 Vue 의 컨셉 은 데코레이터 를 사용 한다 . 데코레이터 로 Vue 옵션 을 클래스 기반 컴포넌트 에 제공 한다 . 클래스 기반 의 컴포넌트 로 오 면서 컴포넌트 프로 퍼티 의 타입 문제 는 아주 깔끔 하 게 해결 되 었 다 . 
 Prop 데코레이터 를 사용 해 todos 가 prop 임 을 정의 하 고 prop 옵션 을 인자 로 전달 한다 . 그리고 타입 은 옵션 이 아니 라 타입 스크립트 의 온전 한 문법 으로 선언 할 수 있 다 . Prop 데코레이터 가 있 는 vue - property - decorator 가 Vue 의 공식 모듈 이 아니 라는 점 만 빼 면 안정 적 이 고 명확 한 방법 이 라고 생각 한다 . 이제 todos 프 롭 을 컴포넌트 에서 사용 할 때 타입 의 도움 을 받 을 수 있 다 . 
 하지만 이번 에 도 문제 는 Vuex 맵 핑 핼 퍼 를 사용 할 때 발생 했 다 . 컴포넌트 에서 mapAction 핼 퍼 를 사용 하 기 위해 Component 데코레이터 를 이용 했 다 . 
 물론 스토어 의 addTodo 라는 액션 은 타입 스크립트 의 타입 을 사용 해 정확 하 게 시그 니 처 정의 를 해 두 었 다고 가정 하 자 . 하지만 이번 에 도 addTodo 는 맵 핑 핼 퍼 의 스트링 인자 로 세탁 되 어 버렸 기 때문 에 컴포넌트 는 addTodo 의 존재 를 유추 할 수 없 다 . 그래서 바로 addTodo 를 컴포넌트 에서 사용 하 려 들 면 컴포넌트 에 없 는 메서 드 를 사용 하 고 있 다고 타입 에러 를 발생 한다 . Vue . extend 같 은 경우 는 맵 핑 핼 퍼 를 사용 할 방법 이 전혀 없 었 지만 클래스 기반 의 컴포넌트 에서 는 사용 할 방법 이 있 다 . 클래스 에서 한 번 더 시그 니 처 를 정의 하 는 것 이 다 . 
 메 서드 의 시그 니 처 를 중복 으로 정의 해서 억지로 끼 어 맞춘 셈 이 다 . 중복 의 문제점 은 로직 이 있 는 코드 에서 뿐 아니 라 타입 정의 에서 도 동일 하 게 존재 한다 . 타입 정의 는 한 번 만 하 고 컴파일러 가 유추 할 수 있 게 해야 한다 . 여러 가지 대안 을 생각 해 보 고 찾 아도 봤 지만 특별히 다른 방법 은 찾 을 수 없 었 다 . 
 고민 을 거듭 한 끝 에 코드 중복 만 은 피해야 한다는 결론 을 내렸 고 ** 맵 핑 핼 퍼 를 사용 하 지 않 기 로 결정 했 다 . ** 맵 핑 핼 퍼 로 맵 핑 되 는 스토어 요소 들 은 컴포넌트 에 따라 적 지 않 은 양 이 될 수 있 는데 타입 까지 중복 으로 정의 하 면 쓸데없이 코드 가 복잡 해졌 다 . 심지어 타입 변경 에 대한 대응 을 생각 하 면 이건 답 이 없 었 다 . 현재 프로젝트 의 컴포넌트 들 은 아래 와 같 은 모습 을 하 고 있 다 . 
 public todos ! : Todo [ ] 
 맵 핑 핼 퍼 를 사용 하 지 않 는 것 외 에 아래 와 같이 Vuex 사용 컨벤션 을 정했 다 . 
 action 이나 mutation 은 특별 한 경우 가 아니 라면 인다 이렉 션 메서 드로 사용 하 지 않 고 각각 dispatch 와 commit 메서 드로 직접 호출 한다 . 잘못 된 타입 의 값 이 인자 로 사용 되 었 을 경우 에 타입 의 도움 을 받 을 수 없 겠 지만 타입 의 중복 은 제거 할 수 있 고 적어도 잘못 된 이름 의 action 이나 mutation 이 실행 되 면 프레임 웍 이 에러 로 알려 주 니 그것 만 으로 충분 하 다 . 
 state 나 getter 는 상황 에 따라 computed 로 정의 하 거나 혹은 $ store 를 통해 직접 사용 하 지만 템플 릿 에서 $ store 의 사용 은 피한다 . 템플 릿 의 복잡도 를 증가 시킬 수 있 다 . 
 이런 컨벤션 을 지키 며 현재 는 고민 없이 타입 스크립트 환경 에서 Vue 컴포넌트 를 개발 하 고 있 다 . 프로젝트 막바지 까지 별다른 문제점 이 없 는 것 으로 보 아 Vue 3 가 나오 기 전 까지 는 이대로 계속 유지 할 것 같 다 . 
 현시점 에서 타입 스크립트 는 Vue 보다 리 액트 와 더 잘 맞 는다고 생각 한다 . 지금 까지 언급 한 것 외 에 도 이런 생각 을 뒷받침 할 큰 차이 가 있 다 . 타입 스크립트 는 TSX 라는 이름 으로 JSX 를 지원 하 기 때문 에 JSX 의 컴포넌트 타입 까지 검증 해 줄 수 있 는 반면 Vue 의 SFC 나 템플 릿 은 아직 지원 하 지 않 는다 . 그래서 컴포넌트 Props 의 타입 을 아무리 잘 지정 한다고 해도 아직 은 반쪽 짜리 사용 이 라고 볼 수 밖에 없 다 . 타입 스크립트 와 Vue 프레임 웍 은 아직 은 시간 이 더 필요 할 듯 보인다 . 하 지만 Vue 3 는 모든 코드 베이스 가 타입 스크립트 로 개발 될 정도 로 커뮤니티 에서 타입 스크립트 를 선호 하 고 있 다 . 아마도 Vue 3 에 는 더 좋 은 방법 이 제시 될 것 같 다 . 얼마 전 에 는 Vue 의 개선 방향 을 고민 하 는 RFC 문서 에 Class API RFC 가 추가 되 었 다 . 아직 논의 가 더 필요 하 겠 지만 전반 적 으로 내용 을 살펴보 니 꽤 괜찮 아 보인다 . 관심 있 다면 참고 하 기 바란다 . 혹시 라도 제안 할 좋 은 대안 이 있 다면 언제 든지 환영 한다 . ( shiren @ nhn . com ) 
 # VueJs # typescript 
 김성호 , FE Development Lab 2019 . 03 . 27 Back to list