9 실 서비스에 타입스크립트를 적용하는 방법 2가지

source: categories/study/vue-beginner-lv5/vue-beginner-lv5_9-00.md

9.0 실습 코드 분석

9.0.1 App.vue

  1. spinner 컴포넌트 사용
    • keyframes로 애니메이션 효과 구현
    • 데이터가 로드되기 전에 나타나는 컴포넌트
    • 사용자로 하여금 데이터가 로드되는 중이라는 걸 인식할 수 있게 해주는 컴포넌트이다.
    • loading이라는 dataprops로 내려준다.
    • loading이라는 propstrue이면 해당 컴포넌트가 랜더링되고, 아니면 랜더링되지 않는다.
    • EventBuson:progress, off:progress 이벤트를 등록해준다.
    • on:progress 이벤트가 감지되면 loading값을 true로, off:progress 이벤트가 감지되면 loading 값이 false가 된다.
    • src/routes/index.js 코드 내용을 보면 5개 라우트로 진입할 때 EventBuson:progress 이벤트가 $emit되도록 설정되어있다.
  2. beforeEnter 사용
    • 해당 라우터에 진입하기 전에.. 즉, beforeEnter가 실행
    • 거기서 on:progress 이벤트 이밋을 하고,
    • store.dispatch를 통해 storeactions 메소드 실행
    • api 호출을 한 뒤에, 성공하면 next()로 해당 라우트로 넘어가도록.. 실패하면 에러 발생
    • 아, api 호출해서 받아온 값은 state.list에 저장
  3. component 호출, 코드를 줄이기 위해 createListView 컴포넌트를 활용, 여기서 render 함수 활용
    • createListView는 일반 함수 형태
    • createListView 함수에 인자 값으로 해당 컴포넌트 이름 전달, 그걸로 해당 컴포넌트 이름 설정
    • 해당 컴포넌트가 mounted되면 off:progress 이벤트 이밋
    • render 함수 실행
      • render 함수의 첫번째 인자는 CreateElement 함수인가봄. 이렇게 설정되어 있는 듯.
      • 그래서 첫번째 인자, 즉, CreateElement 함수에 첫번째 인자로 ListView 컴포넌트 전달
      • ListView에선 ListItem 컴포넌트를 불러오고 있음
      • ListItem 컴포넌트에 들어가면 해당 컴포넌트가 created되면서 아까 api 호출로 저장했던 state.list 값을 꺼내온다.
      • 그리고 꺼내온 state.list 값을 통해 리스트를 랜더링한다.
  4. /news, /ask, /jobs 각 라우트 모두 동일한 형태의 UI를 가진다.
    • 때문에 각 세개의 라우트에 적용되는 컴포넌트를 각각 만들기 싫어 한개의 컴포넌트만 만들고
    • 라우트 name을 통해 각 라우트에 해당하는 api 호출을 보내고 그걸 통해 받아온 데이터로 랜더링하도록 했다.
    • 이것이 좋긴 좋은거 같다. 코드를 줄일 수 있으니까.
    • 하지만 한개의 컴포넌트가 state.list라는 데이터를 바라보고 있게했기 때문에,
    • 그리고 computed를 통해 state.list가 바뀔 때마다 즉각즉각 반응하도록 했기 때문에
    • 원래는 툴바에서 다른 메뉴를 클릭했을 시 -> 스피너가 돌다가 -> 데이터를 다 받아오면 스피너가 꺼지고 -> next() 함수로 해당 컴포넌트로 넘어가면서 해당 컴포넌트의 데이터가 랜더링되어야 하는데,
    • 해당 툴바 클릭하고 데이터 받아오면 next() 되기 전에, 같은 ListItem 컴포넌트에서 storelist 값을 바라보고 있으므로 화면이 한번 바뀌고, 그 다음에 next() 함수 실행, 스르륵 화면전환
    • 여튼 이러한 문제를 해결하기 위해 computed가 아닌 created로..
      • 이러면 단점은.. 데이터가 실시간으로 바뀌어도 화면에 실시간 갱신 기능은 사라진다
      • 그래도 뭐.. 실시간 갱신 기능은 없어도 될듯
      • 그리고 computed 상태라고 실시간 갱신이 되는 것도 아니고.. computed 상태에서 api 호출을 주기적으로 보내서 데이터를 새로 받아오든 웹소켓으로 데이터를 계속 갱신해주던, 뭘 하던지 해야 store의 데이터가 갱신되는거니깐..
      • 그냥 지금 상태에선 created로 바꾸는게 훨씬 좋을듯.
  5. 여튼 코드를 줄인다는 방향성에서는 render 함수를 사용한 이 기법.. 아주 좋은듯.

9.1 프로젝트에 타입스크립트 플러그인 추가

  • @vue/cli 3버전 이상일 때는 기본적으로 프로젝트의 구성이 vue plugin의 집합으로 구성이 되게끔 되어있기 때문에 @vue/cli 3버전 이상으로 프로젝트를 생성하신 분들에 한해서 vue add typescript를 할 수 있다.

vue add typescript

@vue/cli 3버전 이상에선 위와 같은 방법으로 타입스크립트를 추가할 수 있지만, 위와 같은 방법을 추천하지 않는 이유는.. 일단 진행을 해보면서 말씀을 드리겠습니다.

위와 같이 진행하면 처음 cli를 통해 프로젝트를 생성할 때와는 다른 질문들이 나오기 때문에 이런 부분들을 상당히 주의하셔야됩니다.


vue add typescript

 WARN  There are uncommitted changes in the current repository, it's recommended to commit or stash them first.
# 현재 저장소에 커밋안된 변경된 사항이 있다면 우선 커밋하거나 스태쉬 하는 것을 추천한다는 뜻이다.
? Still proceed? (y/N) 
# 진행할까?
# y

? Use class-style component syntax? (Y/n)
# n
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)?
# y
? Convert all .js files to .ts? (Y/n) 
# 모든 자바스크립트 파일을 타입스크립트 파일로 변환할 것인지 묻는 질문입니다.
# 모든 자바스크립트 파일을 타입스크립트 파일로 바꾸면 기본적으로 자바스크립트에서 타입스크립트로 변환되면서 생기는 오류들이 많아지게 됩니다.
# 왜냐면 타입스크립트는 타입이 추가된 언어인거고 자바스크립트는 저희가 원래 사용하던 타입이 없는 언어이다보니까 
# 타입이 필요한 부분에 대해서 전부 다 에러가 발생하거나 
# 혹은 자바스크립트에서 실행하는 시점에서 타입이 바뀌는 그런 유형들을 타입스크립트에서 타입을 강제하기 시작하면서
# 에러가 많이 발생할 것입니다.
# 즉, 이렇게하면 점진적인 적용은 불가능하고 타입스크립트 파일로 변환한 순간부터 전체를 타입스크립트로 바꿔야하기 때문에 이는 no를 선택하는 것이 좋습니다.
# n

? Allow .js files to be compiled? (y/N) 
# 자바스크립트 파일이 컴파일되게 할것인가?
# y

? Skip type checking of all declaration files (recommended for apps)? (Y/n) 
# 모든 선언 파일에 대한 타입체킹을 스킵할 것인가?
# 이런 부분들도 y를 선택해야 점진적인 적용에 도움이 될 것이다.
# y


yarn serve

# 타입스크립트를 추가 후 실행하면, 여기서부터 기존 프로젝트에 타입스크립트를 추가해서 하는 방법을 추천드리지 않는 이유가 발생하는데,

WARNING: You are currently running a version of TypeScript which is not officially supported by typescript-estree.

# yarn serve를 돌릴 때부터 위와 같은 Warning 메시지가 뜹니다.
# 현재 너가 실행한 타입스크립트 버전이 typescript-estree에 의해 지원되는 공식적인 버전이 아니다.
# typescript-estree 란 아무래도 eslint 관련 플러그인 같다.
# 즉 eslint 버전과 맞지 않아서 나는 에러라고 보시면 될 것 같다.

SUPPORTED TYPESCRIPT VERSIONS: ~3.1.1

# 위 문구를 보시면 현재 eslint는 타입스크립트 버전 3.1.1 까지 지원한다고 되어있다.

YOUR TYPESCRIPT VERSION: 4.1.6

# 방금 추가한 타입스크립트 플러그인 버전은 4.1.6 버전이다.
# package.json에 4.1.6 버전으로 명시되어있다.

9.1.1 타입스크립트 추가로 발생하는 문제들

  1. 여튼 위와 같이 타입스크립트를 추가하여 실행했더니 CSS가 조금 깨진다.
    • App.vue 파일을 확인해보시면 타입스크립트 추가할 때 자기 마음대로 App.vue 파일 내용을 바꿔버렸기 때문이다.
    • 즉, App.vue 파일에 우리가 기존에 작성했던 코드들이 다 overriding 된 것이다.
    • 기존 코드로 원복 시켜야된다.
  2. main.ts: main.ts가 다시 한번 쓰여지면서 내용들이 변경이 되었다.
  3. package.json의 기존 라이브러리들도 좀 오래된 라이브러리들도 있어서 호환 문제도 해결해야될 것이다.

그래서 결론적으로는 이런식으로 기존 프로젝트에 vue add typescript를 이용해서 프로젝트를 개선하는 것은 추천드리지 않는다.
타입스크립트를 사용한다는 말은 자바스크립트 최신 스팩을 사용한다는 말이고
그 관련된 생태계도 최신 버전, 그리고 @vue/cli에서 저희가 바로 생성했을 때, 타입스크립트를 끼게되면 그에 맞게 버전들이 설정되어 다 호환이 될 것인데,
이건 중간에 끼워넣다보니까 호환 문제도 발생하고..

그래서 결론적으로 이런 방식으로 타입스크립트를 적용하지 않고 다른 방식으로 적용하는 방법에 대해 알아보도록 하겠다.

역순으로..

  1. 타입스크립트가 적용된 프로젝트를 생성하고
  2. 기존 프로젝트 코드를 거기다 적용하는 식으로..

위와 같이 진행해본다는 뜻인듯!!

Note

9.2 프로젝트 구성 및 실행 결과 확인

Note

9.2.1 프로젝트 구성 및 실행 결과 확인 vue-news 원복


vue create vue-news-ts

Vue CLI v4.5.15
? Please pick a preset: 
  Default ([Vue 2] babel, eslint) 
  Default (Vue 3) ([Vue 3] babel, eslint) 
❯ Manually select features 

? Please pick a preset: Manually select features
? Check the features needed for your project: 
 ◉ Choose Vue version
 ◉ Babel
❯◉ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
❯ 2.x 
  3.x 

? Use class-style component syntax? (Y/n) n

? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n) y

? Pick a linter / formatter config: 
  ESLint with error prevention only 
  ESLint + Airbnb config 
  ESLint + Standard config 
❯ ESLint + Prettier 
  TSLint (deprecated) 

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files 
  In package.json 

? Save this as a preset for future projects? (y/N) n
# Y 선택시 vue create 명령어 실행 때마다 지금 선택한 preset 대로 프로젝트가 생성될 것이다.

Note

9.2.2 프로젝트 구성 및 실행 결과 확인, 타입스크립트 적용한 프로젝트 생성

Note

9.2.3 프로젝트 구성 및 실행 결과 확인, 기존 프로젝트 코드를 타입스크립트가 추가된 프로젝트로 옮기기 (점진적으로)

  1. 우선 src 폴더 안에 있는 모든 폴더(api, assets, components, routes, store, utils, views)를 옮기자.
    • 그러기 위해선 타입스크립트를 추가하여 새로 생성한 프로젝트의 assets, components 폴더를 삭제한다.
    • 그리고난 후, 옮긴다.
  2. App.vue 파일도 그대로 들고오자. (복붙)

  3. main.js 내용도 그대로 들고온다. (복붙)

    이렇게 에러가 나야지 정상이다.

  4. public/index.html 파일도 그대로 옮겨준다. (복붙)

  5. yarn add axios vuex vue-router

  6. yarn serve
    • 에러가 많이난다. 에러가 많이 나야 정상이다.
    • 왜냐하면 자바스크립트 파일을 타입스크립트에다 넣었기 때문에 에러가 많을 수밖에 없다.

강의에선 타입스크립트 에러가 발생해도 일단 실행은 된다.
타입스크립트 에러랑 기능 에러는 별개니깐.
그런데 내꺼는 실행되지 않네..

강의에서 타입스크립트 버전은 3.9.7인가 그렇고 내가 실습할땐 4.1.6인데, 버전 차이에서 오는 차이인걸까?
뭔지 모르겠네..

9.3 타입스크립트 프로젝트 진행 방식 안내

타입스크립트를 점진적으로 적용하기 위해 강의에선

  1. 아예 새로운 타입스크립트가 추가되어있는 프로젝트를 생성하고
  2. 기존 코드를 새로 생성한 프로젝트로 옮겨서 타입스크립트 에러를 해결하는 식으로..
  3. 어차피 실행은 되니깐

그래서 위와 같이 하려고 했으나
막상 해보니 실행이 안되는 상태..

강의와 현재 차이점은 강의에서 타입스크립트 버전이 3점대 버전이라면, 지금 내가 실습할 땐 4점대 버전..
이 버전 차이가 있는 건지..

Note

9.3.1 질문

뷰 프로젝트에 타입스크립트를 점진적으로 적용하기 위해

  1. 타입스크립트가 추가된 새로운 프로젝트 생성
  2. 해당 프로젝트로 기존 코드들을 옮긴 후 타입스크립트 점진적으로 적용

위와 같이 하는 이유

  • 일단 실행은 되니깐. 타입스크립트 에러가 나도. CSS도 기존 그대로 유지되고

이렇게 이해를 했는데요,위와 같이해도 실행이 제대로 되지 않네요.강의에서는 타입스크립트 에러는 많이 발생하지만 localhost:8081에 화면은 제대로 나오잖아요?그런데 저는 화면 조차도 제대로 나오지 않네요.

Could not find a declaration file for module ‘./store/index.js’. ‘/Users/…/src/store/index.js’ implicitly has an ‘any’ type.

위와 같은 에러가 발생합니다.아무래도 모듈을 제대로 못가져오는거 같은데..

현재 강의 시점의 타입스크립트 버전이 3버전이고지금 타입스크립트 버전이 4점대 버전인데,주버전이 달라져 생긴 문제인건지 궁금합니다.

9.3.2 뷰 프로젝트에 타입스크립트를 점진적으로 적용하는 방법

  1. Vue + TypeScript 프로젝트 생성
  2. 기존 서비스 코드와 라이브러리를 새 프로젝트에 이동
  3. 기본적인 빌드 에러 해결
  4. 타입스크립트의 혜택을 볼 수 있는 주요 파일들 위주로 .js -> .ts로 변환하며 적용

팁: 타입 체킹 정도는 덜 엄격한 방식에서 점점 엄격한 방식으로 적용하는 것을 추천

Note

여튼 버전업이 강의 내용과 현재와 다른거에 영향을 끼치는건 사실인 것 같다.