저장소를 git clone
한 후 , 필요한 package 를 추가적으로 설치한다.
npm install -g typescript
: typescript 패키지@types/react
@types/react-dom
: 타입 정의 파일@typescript-eslint/eslint-plugin
@typescript-eslint/parser eslint
: typescript-eslint 적용하기 위한 typescript, eslint, typescript-eslint 관련 패키지eslint-config-prettier
eslint-plugin-prettier
eslint-plugin-react
eslint-plugin-react-hooks
prettier
: typescript-eslint + prettier 적용 관련 패키지vsCode 에서 tsconfig.json을 참고해서 타입스크립트 문법을 검사한다. 뿐만 아니라 웹팩에서 설정할 ts-loader가 이 파일을 참고해서 트랜스파일 작업을 하기 때문에 tsconfig.json 파일은 먼저 생성해야 한다.
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["es6", "dom"],
"rootDir": "src",
"module": "CommonJS",
"esModuleInterop": true,
"target": "es5",
"sourceMap": true,
"moduleResolution": "node",
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"allowJs": true
},
"include": ["./src"],
"exclude": ["node_modules", "build"]
}
jsx: .tsx 확장자의 컴파일 결과 JSX 코드를 컴파일할 방법 결정
lib: 컴파일에 필요한 JavaScript 내장 라이브러리 지정
rootDir: 루트 디렉토리 기준 변경하는 것으로 js 아웃풋 경로에 영향
module: 프로그램에서 사용할 모듈 시스템 (target 프로퍼티가 es5로 지정되었을 때 CommonJS 로 지정)
esModuleInterop: 모든 가져오기에 대한 네임스페이스 객체 생성을 통해 CommonJS와 ES 모듈 간의 상호 운용성 제공
target: 컴파일할 JavaScript 버전 지정
sourceMap: 컴파일된 파일 디렉터리에 .js.map 파일 생성 설정
moduleResolution : module 프로퍼티에 따라 결정하는 것으로 모듈 분석 방법을 설정
allowJs: JavaScript 파일 컴파일 허용
// 엄격한 유형 검사 옵션
noImplicitReturns: 함수에서 return 없으면 에러
noImplicitThis: 명시적이지 않은 any 유형으로 this 표현식 사용시 에러
noImplicitAny: 명시적이지 않은 any 유형으로 표현식 및 선언 사용시 에러
strictNullChecks: 엄격한 null 검사 사용
ESLint: JavaScript 의 문법을 확인해주는 도구
module.exports = {
root: true,
env: {
browser: true,
node: true,
},
extends: [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
],
rules: {
"prettier/prettier": [
"error",
{
doubleQuote: true,
semi: true,
useTabs: false,
tabWidth: 4,
printWidth: 80,
bracketSpacing: true,
arrowParens: "avoid",
},
],
},
parserOptions: {
parser: "@typescript-eslint/parser",
},
};
vsCode 익스텐션에서 eslint
와 prettier
를 설치해준다.
이를 통해 오류를 검사할 수 있다.
설정을 다 마친 후, .js
를 .tsx
파일명을 변경해준다.
그러면 수많은 오류들이 터미널과 파일에 빨간줄을 통해 출력이 된다.
포팅하는 법은 타입 지정, props 들을 type이나 interface 로 설정해준다.
type TodoProps
으로 생성해준다.TodoProps
의 프로퍼티로는 빨간줄로 표시된 오류에서 id
, text
, isComplete
를 찾아낼 수 있다. 각각의 타입을 number
, string
, boolean
으로 지정해준다.type TodoProps = {
id: number;
text: string;
isComplete: boolean;
}
useState
로 todos
로 생성이 되어 있는데 여기서 타입을 추가해주는데 todos는 todo를 배열형식으로 만든 것이기 때문에 타입을 형식에 맞춰 작성한다.const [todos, setTodos] = useState<TodoProps[]>([]);
addTodo
, removeTodo
, completeTodo
에는 각각 todo
, id
, id
가 매개변수로 필요한 것을 알고 있고 이것을 타입만 지정해주면 된다.const addTodo = (todo: TodoProps) => {...}
const removeTodo = (id: number) => {...}
const completeTodo = (id: number) => {...}
todos
, completeTodo
, removeTodo
임을 알 수 있고 이 프로퍼티를 interface TodoListProps
로 설정해준다.interface TodoListProps
안의 프로퍼티들은 각각의 타입을 지정해준다. 이때 App 에서 만들어준 TodoProps
를 사용한다.todos
는 todo
를 가르키는 TodoProps
를 배열화 한 것이다.completeTodo
와 removeTodo
는 매개변수를 id
로 받는 void
형 함수이다.interface TodoListProps{
todos: TodoProps[];
completeTodo(id:number):void;
removeTodo(id:number):void;
}
function Todo({props}:TodoListProps){ ... }
props로 받은 onSumbit
이벤트 함수를 interface TodoForm
으로 지정해준다.
이때, 전달인자는 isComplete
프로퍼티가 빠진 TodoProps
타입을 알 수 있으며 void 형인 함수이다.
interface TodoFormProps {
onSubmit(todo: TodoProps):void;
}
const [input, setInput] = useState<string>("");
const [number, setNumber] = useState<number>(1);
TodoProps
TodoForm
에서 알 수 있듯이 onSubmit
함수의 전달인자는 todo
인데, 그 중 isComplete
프로퍼티는 생략이 된 것을 알 수 있다. 따라서 todo를 나타내는 TodoProps type
에서 isComplete
프로퍼티는 생략가능한 프로퍼티이므로 ?
키워드를 추가한다.TodoProps
는 TodoForm
과 Todo
컴포넌트에 사용되어 각각의 파일에서 import
를 해준다. import
를 해주기 위해서는 해당 App
폴더에서 export
를 해주어야만 다른 파일에서 사용가능하다.e.target.value
를 전달하기 위해 매개변수 e
가 필요하다. 타입을 잘 모르겠어서 any
로 설정해주었는데 기본값이 any형식으로 포함이 되기 때문에 굳이 설정해줄 필요가 없고 더 명확하게 타입을 명시해야 한다.onSumbit 은 React.FormEvent
관련 이벤트 타입으로 <HTMLFormElement>
요소 타입이다.
onChange 는 React.ChangeEvnet
관련 이벤트 타입으로 <HTMLInputElement>
요소 타입이다.
그러다 useRef 가 사용되는 곳에서 마우스를 대 보니 <HTMLInputElement>
요소 타입인 것을 알아냈고, 위 이벤트 핸들러처럼 사용하였다.
하지만 타입을 지정해주어도 useEffect 내에서 inputRef.current 에 빨간줄 오류가 떴고, 이 값은 null 이 될 수도 있다는 뜻이었다.
null을 해결해주기 위해서 해당 분기를 해주었는데, 이보다 더 나은 방법은 없을까,,,??
키워드를 사용해서 선택적으로 null이 아닌 값만 자동적으로 받을 수 있게 수정하였다.
index.tsx 에서도 타입을 지정해주어야 했는데, document.getElementById()
는 HTMLElement | null
형식이라고 도움을 주었다.
따라서 as
타입 단언을 이용해 HTMLElement
타입을 지정해주었다.
이론은 참 쉽게 느껴지고 포팅을 마치 후에는 그닥 어렵지 않은데 왜 시작이 항상 어려운지 모르겠다.
내 문제는 항상 어렵다고 회피하기 일수였지만, 이번 TIL 을 통해 조금이나마 포팅하는 방법을 외우는 방법이 아닌 이해하는 형식으로 배우게 되었다.
어렵게 생각하지말고 낯설다 라고 되뇌이며 노력해보자!