이전에 React와 Javascript로 제작했던 자기소개 사이트 개인 프로젝트가 있었는데,
내용 업데이트도 해야하고, 요새 TypeScript를 공부하고 있다보니 연습도 해볼 겸 이를 적용해서 바꾸고 싶었다.
CRA로 시작할 때 TS세팅하는 법은 아는데 이미 JS로 작업된 프로젝트를 바꾸는 과정은 이번이 처음이었다. 흠.. 일단 시작!
일단 첨에 그냥 본능적으로 '아 TS 작성법 아니까 다 변환하고 type넣어야지~'하고 .ts
로 바꾸고 작업하려 했는데 뭐.. 당연한 얘기지만 안 됐다ㅋㅋ
이 프로젝트 dependency안에는 TS패키지가 없어서 TS설치가 먼저였다. 설치 명령어는 아래를 입력하면 된다.
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
yarn add typescript @types/node @types/react @types/react-dom @types/jest
명령어를 실행하면 위처럼 package.json에 typescript와 관련된 패키지들이 설치된 것을 확인할 수 있다.
이제 tsconfig.json
파일 추가를 위해 아래 명령어를 입력하면,
npx typescript --init
안된다..? 응? 위처럼 에러가 뜬다.
npm ERR! could not determine executable to run
npm ERR! A complete log of this run can be found in: ~~
왜지. 왜일까.. 그래서 한번 찾아보니 명령어 자체가 잘못되었다.
stackoverflow에서 질문된 내용의 답변에 따르면 위 명령어가 아니라 아래와 같이 입력해야한다고 한다.
npx tsc --init
이번엔 다행히 성공적으로 설치되었다!
오! 성공!..인데 이건 또 뭐지..
분명 tsconfig.json파일이 생성되었다. 그런데 에러가 뜨길래 파일을 열고 확인해보면 기본값으로 생성된 파일 첫줄에 빨간 밑줄이 가있고,
아래같이 "구성 파일에서 입력을 찾을 수 없습니다." 문구가 뜬다.
그래서 이건 또 무슨 문제인가 하고보니, tsconfig로 typescript 프로젝트에 대한 설정을 했으면서 정작 현재 프로젝트 내엔 ts파일이 없어서 생긴 문제였다.
그래서 확인을 위해 임시로 ts파일을 하나 만들어 보니 경고문이 없어진다.
경고문의 원인을 알았으니 다시 tsconfig를 설정하고 프로젝트 내의 파일들을 ts(tsx)로 바꿔보자.
위 명령어로 설정하면 tsconfig.json
에서 사용할 수 있는 옵션값들이 쭉~ 나온다.
그걸 입맛에 따라 사용하면 될 것이나, 나는 일단 타입스크립트 핸드북에서 말하는 기본설정으로 해놓고 진행했다.
{
"compilerOptions": {
"allowJs": true,
"target": "ES5",
"outDir": "./dist",
"moduleResolution": "Node",
"lib": ["ES2015", "DOM", "DOM.Iterable"]
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "dist"]
}
.jsx
였던 파일을 .tsx
로 바꾸자마자 뜬 경고문.
- ~~모듈은 'esModuleInterop' 플래그를 사용하는 가져온 기본값이어야만 합니다. ts(1259)
- index.d.ts(63, 1): 이 모듈은 'export ='를 사용하여 선언되었으며 'esModuleInterop' 플래그를 사용하는 경우에만 기본 가져오기와 함께 사용할 수 있습니다.
이 구문은 다음과 같이 import코드를 약간만 수정하면 해결이 가능하다.
import * as React from "react";
바로 * as
를 붙여주는 것. 그치만 이걸 매번 하기 번거로울 수 있다.
그러니 tsconfig
에 아래 옵션을 추가해준다.
{
"compilerOptions": {
// ...
"esModuleInterop": true,
// ...
}
}
그러면 아래와 같이 * as
를 사용하지 않아도 문제가 해결된다.
'~~.json' 모듈을 찾을 수 없습니다. '--resolveJsonModule'을 사용하여 '. json' 확장명이 포함된 모듈을 가져오는 것이 좋습니다. ts(2732)
이젠 에러가 익숙하다. 애초에 처음이고, 처음부터 typescript로 시작하는게 아니라 js를 ts로 바꾸는거니까 (자기합리화..)
이것도 코드 사용법을 조금 바꿔 에러를 없앨 수 있다.
export const Portfolio = () => {
const data = require("../../data/portfolio.json");
//...
return (
// ...
)
}
위처럼 commonJS에서의 모듈 사용법으로 require
을 이용해 코드를 수정하면 에러를 없앨 수 있다.
json에 대해 export객체를 변수안에 담는 것이기 때문에 최상단이 아닌 컴포넌트 안에 작성해야한다.
에러가 사라졌다!
그렇지만 이것도 매번 이렇게 작성하기 번거로울 수 있다. 적어도 나는 ㅎㅎ
{
"compilerOptions": {
// ...
"resolveJsonModule": true,
// ...
}
}
위 옵션을 추가하면 ES6의 방법으로 import가 가능해져 일괄 해결 가능하다.
'~~.jpg' 모듈 또는 해당 형식 선언을 찾을 수 없습니다. ts(2307)
이번엔 이미지를 가져오는 방식에 모듈 선언 에러가 뜬다.
이에 대한 해결방법을 아까 위에 썼던 require
을 적용해본다면?
const myPic = require('경로');
해결은 된다. 그런데 위처럼 'import(가져오기)로 변환될 수 있습니다.'라는 문구가 떠서 조금은 거슬린다.
이것까지 해결하려면 어떻게 해야할까?
일단 먼저 루트 위치에 types라는 이름의 폴더를 만든다. 이 폴더에는 앞으로 declare
즉, 프로젝트내 타입에 대한 선언정보를 담을 파일이 위치할 것이다.
types
폴더 만들기 (사용자정의 가능)image.d.ts
라는 파일 생성tsconfig.json
안에 아래 옵션 추가{
"compilerOptions": {
// ...
"typeRoots": ["types", "./node_modules/@types"],
// ...
}
}
옵션명 그대로 type에 대한 정보가 담긴 파일들의 루트를 지정해준다.
.d.ts
라는 확장자명의 의미는?이 확장자명에서
d
에 집중하면 의미 유추가 가능하다. 이미 위에서 언급했던 declare를 의미하는 것으로 프로젝트 내 type들을 선언하는 내용이 담기는 파일을 의미한다.
기존에 사용하던 몇가지 라이브러리에 @types 패키지를 추가해줘야한다.
그중에 대중적이고 type패키지의 추가가 필요한 두가지가,
요렇게이다. 아래 명령어를 통해 패키지를 설치해보자.
install @types/react-router-dom -D
install @types/styled-components -D
index.ts와 App.ts에서 발생한 에러들
- Parsing error: '>' expected.eslint
- 'BrowserRouter'은(는) 값을 참조하지만, 여기서는 형식으로 사용되고 있습니다. 'typeof BrowserRouter'을(를) 사용하시겠습니까? ts(2749)
- '<' 연산자를 'boolean' 및 'RegExp' 형식에 적용할 수 없습니다. ts(2365)
- 1개의 인수가 필요한데 2개를 가져왔습니다. ts(2554)
허어어 이번엔 App.ts
와 index.ts
에서 발생한 에러들이다. .js
를 .ts
로 바꾸니까 에러 대잔치인데 왜 이렇게 정보가 없지..
그래서 뒤적뒤적 계속 구글링을 해보고, 이전에 CRA부터 typescript를 적용했던 프로젝트의 내용을 보다가 깨달았다...
.ts가 아니라 .tsx
를 썼어야 했다는거.. jsx는 tsx로 js는 ts로 바꾸다보니 index와 App도 모두 자연스레 ts로 바꿔버렸던 것.
확장자를 ts에서 .tsx
로 바꿔주면 바로 해결이다. 명령어로 초기세팅을 하는게 아니라 직접 파일들을 바꿔주다 보니 이런 사소한 차이로도 결과가 달라져 버린다;;
위 과정을 모~두 거치고 최종적으로 실행해본 결과는? 다행히도 성공!
type을 지정할 것들이 특별히 있지 않아서 리팩토링이 엄청 어려운 것은 아니었지만 그래도 처음 하다보니 이런 사소한 성공도 엄청 뿌듯하다.
깃헙에 push까지 완료! before & after
그 동안에는 어떤 문제를 해결하면서 자료를 수집하고 정리해놓기는 해놓았지만 과정에 대한 디테일을 바로바로 기록하진 않았었다.
이것저것 할 것 많다는 핑계로 나중에 써야지하고 미루고 미뤘기 때문..(근데 진짜 많기도 하고..)
그런데 이번에 js프로젝트를 ts로 리팩토링하면서 조사했던 자료를 그때그때 메모하고 필기하고, 마치 일기쓰듯이 이렇게 기록했봤는데 앞으로도 이렇게 해야겠다.
맘먹고 하면서 정리하니 더 뿌듯하고 좋다!
왕감사합니다