안녕하세요. TypeScript 카테고리를 새로 만들었습니다. 이 카테고리에는 제로초 블로그를 타입스크립트로 전환한 후기를 남겨보려 합니다. 사실 타입스크립트 강좌를 쓰려고 했는데 공식 문서가 너무 잘 되어 있어 JS 프로젝트를 타입스크립트로 전환하는 과정을 보여드리는 게 더 좋을 것 같다고 판단했습니다.
타입스크립트 학습 꿀팁을 드리자면 공식 문서 를 한 번 쭈욱 읽은 후 What's New 부분을 추가로 한 번 더 읽어보시면 됩니다. 타입스크립트 기능들이 어떻게 추가되어 왔는지를 알 수 있어 편합니다.
시간이 남는다면 강좌도 한 번 써보겠습니다(나중에 타입스크립트 교과서나 deno 교과서 집필도 한 번... ㅋㅋㅋ).
타입스크립트 전환 이유
제 블로그는 항상 최신 기술을 접목하는 것을 원칙으로 하고 있었습니다. 그러다가 회사 일을 하고 몸이 지치니 점점 블로그 업데이트가 뜸해 지더군요(게시글은 그래도 1주일에 한 번 포스팅했지만요). 그래서 리프레쉬하고자 블로그를 타입스크립트로 전환해보았습니다. Redux에 reselect도 붙이고요.
사실 타입스크립트가 굳이 필요하다고 생각하지는 않지만, 타입스크립트를 배우고 적용하는 노력 대비 얻는 이점(약타입에서 강타입으로 가는 이점)이 크다고 판단했습니다. 회사에서도 타입스크립트로 개발하고 있어서 적응에 문제는 크게 없었습니다. 단, 4만 줄이나 되는 블로그의 js 코드를 수정하는 것이 문제였죠. 이제부터 어떻게 수정했는지 보여드리겠습니다.
환경 설정
일단 js 파일들을 ts로, jsx를 tsx로 바꾸고, 바벨을 타입스크립트로 바꾸는 과정이 필요합니다. 웹팩을 같이 사용하기 때문에 웹팩에 타입스크립트를 처리할 로더도 붙여주고요. 아래 코드들은 실제 코드라기 보다는 전환 과정을 표현하기 위한 코드로 보시면 됩니다.
npm i typescript awesome-typescript-loader
webpack.config.js
{
module: {
rules: [{ test: /\.tsx?$/, loader: 'awesome-typescript-loader' }], // 바벨 지우고 추가
},
resolve: {
modules: [path.join(__dirname, '..', 'app'), 'node_modules'],
extensions: ['.css', '.tsx', '.ts'], // js jsx 대신 ts tsx 추가
},
}
타입스크립트 세팅도 해줍니다.
tsconfig.json
{
"compilerOptions": {
"outDir": "./dist",
"allowJs": true,
"target": "es5",
"lib": [
"es2015",
"es2016",
"es2017",
"es2018",
"dom",
"webworker"
],
"jsx": "react",
"module": "esnext",
"moduleResolution": "node",
"noImplicitReturns": true,
// "noImplicitThis": true,
// "noImplicitAny": true,
// "strictNullChecks": true,
"downlevelIteration": true,
"sourceMap": true,
"typeRoots": [
"./types",
"./node_modules/@types"
]
},
"include": [
"./**/*"
],
"exclude": [
"node_modules"
]
}
실제로 전환할 때는 allowJs를 true로해서 일부 파일만 ts로 바꾸는 것이 좋습니다. 제 블로그만 해도 코드가 4만 줄인데 그걸 한 번에 다 바꾸는 것은 쉽지 않습니다. 점진적으로 바꿔 나가는 것을 추천드립니다.
target은 es5로 해서 바벨을 대체했고, lib은 타입스크립트가 기본적으로 제공하는 타입들을 활성화시키는 것입니다. 블로그가 PWA이기 때문에 webworker도 넣었습니다. jsx는 리액트를 쓰기 때문에 필요하고요. module은 exnext로 해서 dynamic import(코드 스플리팅)를 쓸 수 있게 하였습니다. moduleResolution은 노드 기반이라 node를 썼고요. downlevelIteration은 이터레이터를 호환하기 위한 설정입니다.
noImplicit 시리즈가 타입스크립트의 핵심입니다. 이것들을 다 true로 켜 놓아야 진정 타입스크립트를 한다고 할 수 있습니다. 하지만 처음 전환 과정에서는 수정할 것들이 너무 많아지기 때문에 일단 주석 처리해두고, 세팅 완료 후 주석을 풀고 작업할 예정입니다.
typeRoots를 보시면 types와 node_modules/@types 폴더가 있습니다. 타입스크립트는 여기서 타입 정의들을 읽습니다. types는 제가 만든 타입 정의이고요. @types는 보통 외부 라이브러리들의 정의입니다.
이제 기존 라이브러리들에 타입을 추가해야 합니다. 직접 추가할 수는 당연히 없고, 타입스크립트 커뮤니티에서 유명한 패키지들은 다 타입을 만들어 두었습니다. 바로 DefinitelyTyped입니다. npm에서 @types로 시작하는 패키지들을 다운받으면 됩니다.
package.json
{
"dependencies": {
"@types/classnames": "^2.2.6",
"@types/cookie-parser": "^1.4.1",
"@types/cors": "^2.8.4",
"@types/crypto-js": "^3.1.43",
"@types/draft-js": "^0.10.25",
"@types/express": "^4.16.0",
"@types/express-session": "^1.15.11",
"@types/gravatar": "^1.4.28",
"@types/helmet": "0.0.41",
"@types/hpp": "^0.2.1",
"@types/method-override": "0.0.31",
"@types/mongoose": "^5.2.17",
"@types/morgan": "^1.7.35",
"@types/node": "^10.10.3",
"@types/passport": "^0.4.6",
"@types/passport-facebook": "^2.1.8",
"@types/passport-google-oauth2": "^0.1.2",
"@types/passport-kakao": "^0.2.0",
"@types/passport-local": "^1.0.33",
"@types/passport-naver": "^0.2.0",
"@types/passport-twitter": "^1.0.34",
...
}
}
이런 식으로 기존 패키지들을 거의 다 설치하면 됩니다. 가끔가다 axios나 moment처럼 스스로 타입을 제공하는 라이브러리들이 있지만, 많지는 않습니다.
마지막으로 ts-node를 설치합니다. ts 파일을 바로 노드에서 돌릴 수 있게 해주는 패키지입니다. 성능 문제가 있으니 개발용으로만 쓰고, 배포 시에는 타입스크립트를 자바스크립트로 컴파일 한 후 실행해야 합니다.
npm i -D ts-node
nodemon.json
{
"ext": "css json ts tsx",
"exec": "npm run clean && npm run build:dev && ts-node server/index"
}
이제 세팅은 끝났습니다. 확장자만 js에서 ts로 바꿨기 때문에 엄청난 에러들이 발생합니다. js 코드를 타입스크립트 기반으로 바꾸는 과정이 필요합니다. 그 과정을 차례로 알아보겠습니다. 다음 포스트에서 import export 부분부터 시작합니다.
혹시 현재 만들어진 블로그는
프론트엔드 프레임워크를 이용해서 만든건가요(vue,react)?