이 포스팅은 React에 TypeScript를 적용하는 방법에 대한 포스팅입니다.
React에서 PropTypes로 충분히 타입 체킹이 가능하지만 state, function parameters 등의 타입 체킹은 할 수 없다. 그래서 TypeScript를 적용해보고자 합니다.
React의 기본 세팅이 되어있지 않다는 전제하에 TS를 함께 세팅해보겠습니다.
프로젝트를 시작할 폴더를 만든후 그 폴더 안까지 이동한다.
> npm init
커멘드 창에 package.json 파일을 세팅하는 명령창이 뜬다.
"author" 키워드⇨ 자신의 이름이나 원하는 것을 쓰고
"license" 키워드 ⇨ "MIT"
나머지는 그냥 엔터
> Is this OK? ⇨ yes
package.json 파일에서
"scripts": {
"dev": "webpack"
},
npm run dev를 실행하면 webpack이라는 명령어가 실행되게 해준다. (OR > npm webpack)
npm i typescript
로 TypeScript 컴파일러를 설치한다. 이후 명령어는 tsc를 사용할 수 있다.
> npm i react react-dom
(웹 환경: react-dom / 앱 환경: react-native)
> npm i webpack webpack-cli -D
( -D : 개발용 )
타입스크립트는 자체 컴파일러가 있기 때문에 따로 바벨을 쓰지 않아도 된다. (같이 사용하는 경우도있음.)
⇨ 더 자세한 설명
( ※ 리액트만 사용했을때는 babel을 통해서 바꿨다.
⇨ 바벨로더를 붙여서 바벨과 웹팩을 이어줌 )
로더를 사용하여 타입스크립트와 웹팩을 연결(?)해준다.
: ✅ TS나 해당 loader들의 버전이 맞지 않아서 에러가 생길 수 있다! 주의해서 사용해야한다.
> npm install --save-dev typescript ts-loader
> npm install awesome-typescript-loader -D
: awesome-typescript-loader의 문서에서는 다음과 같이 주장하고 있다.
ts-loader와의 차이점
- Babel과 함께 Typescript를 사용하는 사람들에게 유용 할 수 있습니다.
- 빠르다. (웹팩 컴파일이 더 일찍 종료되고 브라우저에서 컴파일 된 버전을 탐색 할 수 있습니다.)
TS와 Babel을 같이 쓰는 경우를 대비해서 awesome-typescript-loader를 사용해도 된다.
React와 React-dom은 JS로 만들어져있고 타이핑을 제공하지 않는다. 따라서 React와 React-dom의 타입은 알지 못한다.
하지만 DefinitelyTyped TS커뮤니티의 형님들이 해당 라이브러리들의 타입들을 만들어주셨다. ( React / React-dom )
> npm i @types/react @types/react-dom
TS로 만들어진 라이브러리는 따로 @types/___ 와 같은 타입을 받을 필요가 없다.
여기까지 수행하면, 다음과 같은 package.json 파일이 다음과 같이 설정된다.
{
"name": "ts-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack"
},
"author": "Kihyeon",
"license": "MIT",
"dependencies": {
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"typescript": "^4.2.3"
},
"devDependencies": {
"awesome-typescript-loader": "^5.2.1",
"webpack": "^5.30.0",
"webpack-cli": "^4.6.0"
}
}
> tsc --init
위의 커멘드로 tsconfig.json을 생성할 수도 있다. 이렇게 하면 사용할 수 있는 컴파일러옵션이 모두 생성되는데 이는 다른 포스팅에서 공부한 후 정리해보아야겠다.
TS DOC | Intro to the TSConfig Reference
직접 생성하면,
{
"compilerOptions": {
"strict": true,
"lib": ["es5", // 꼭 필요한 것만 적어도 좋다!
"es2015",
"es2016",
"es2017",
"es2020",
"dom"
],
"jsx": "react"
}
}
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development', // 배포용: production
devtool: 'eval', // 배포용: hidden-source-map *그냥 source-map을 쓰면 개발자 도구에 소스코드가 노출이 된다.
resolve: {
extensions: ['.jsx', '.js', '.tsx', '.ts'], // 웹팩에서 처리해주는 확장자들
},
entry: {
app: './client', // app.js를 만들어낼 파일
},
// modules, plugins에 적힌 처리과정을 client.tsx에 적용을 해서 최종적으로 app.js를 뽑아낸다(output).
module: {
rules: [
// babel대신에 tsc 설정.
{
test: /\.tsx?$/, // tsx나 ts파일을 발견하면
loader: 'awesome-typescript-loader', // 해당 loader를 통해서 버전을 변환하겠다 는 뜻.
},
],
},
plugins: [], // 현재는 필요없어진 옵션이라고 한다.
output: {
filename: 'app.js', // or '[name].js'
path: path.join(__dirname, 'dist'), // npm webpack을 실행하면 client.tsx를 통해서 webpack처리 후 dist폴더가 생기고 그 안에 app.js가 들어있다.
},
};
npx webpack 을 실행하면 client.ts를 통해서 빌드를 하게된다. 그 결과 물로는 dist안에 app.js가 생성된다. (웹팩이 만들어낸 결과물은 ./dist/app.js 이다.)
따라서
순수TS로 작업할 때와는 웹팩이나 loader 등을 쓰기 때문에 다소 다른 점이 존재하는 것 같습니다.
순수TS로는 작업할 일이 크게는 없을 것 같아서 따로 정리는 하지 않았지만 "React + TS" 조합은 거의 국룰 조합이기 때문에 한번쯤은 정리해두는 것도 좋은 것 같습니다.