오늘...
기존 JavaScript로 작성했던 프로젝트(초기 단계)를 TypeScript로 리팩토링하는 데에 성공했다.
오늘내로 컴파일이 될까 싶을 정도로 에러 화수분이었던 상황...
오전 10시부터 시작한 에러 대환장파티를 오후 4시에 마무리 짓는 데에 성공한다.
그 과정에서 기억하고 싶은 에러를 담아본다.
(TypeScript를 배운 지 3일차 타둥이의 글입니다.. 저와 같은 타입스크립트 스타터들을 위한 포스트임을 감안해주시길 바랍니다..🥺)
JavaScript로 작성하던 React 프로젝트를 TypeScript로 리팩토링하기 위해서는,
초기 CRA 명령어인 $ npx create-react-app ts-react-tutorial --typescript
이 아니라,
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
이 명령어를 사용해야 합니다. (yarn add -g typescript
도 필요합니다)
js와 jsx 파일을 모조리 ts, tsx로 바꾸어 주세요.
tsconfig.json 파일을 작성해야 합니다. (참고: tsconfig.json 사용하기)
기존에 사용하던 JavaScript용 라이브러리는 TypeScript용을 찾아서 다시 설치해야 합니다.
"@types/lodash": "^4.14.149", "@types/react-slick": "^0.23.4", "@types/redux-logger": "^3.0.8"
등등...
자 이제 터미널에 뜨는 컴파일 오류를 하나씩 없애나가면 됩니다.
+@ IDE로 VSCode를 사용하시는 경우, 이 과정에서 VSCode가 정신을 못차립니다. 서버를 다시 껐다가 재시동하는 방법, node_modules를 삭제해서 다시 yarn install 해주시거나, VSCode 창을 완전히 껐다가 다시 켜는 방법.. 등 온갖 수단과 방법을 가리지 말고 시도해보세요 😇
Property 'kakao' does not exist on type 'Window & typeof globalThis'. TS2339
declare global {
interface Window {
kakao: any;
}
}
const { kakao } = window;
외부 API인 kakao를 사용할 때, window 객체에 대한 정의가 필요했던 상황.
window의 interface를 선언함으로써 간단히 해결
div에 onClick 이벤트를 걸어놓은 상황에서 event의 타입을 정의해야 했던 상황.
event: any로 처리해도 컴파일이 가능했지만 확실한 해결책을 찾고 싶었다.
결과적으로 다음과 같은 interface를 export해서 해당 컴포넌트에 import 한 후 사용하는 방법을 택했다.
export interface BaseSyntheticEvent<E = object, C = any, T = any> {
nativeEvent: E;
currentTarget: C;
target: T;
bubbles: boolean;
cancelable: boolean;
defaultPrevented: boolean;
eventPhase: number;
isTrusted: boolean;
preventDefault(): void;
isDefaultPrevented(): boolean;
stopPropagation(): void;
isPropagationStopped(): boolean;
persist(): void;
timeStamp: number;
type: string;
}
const tabHandler = (event: BaseSyntheticEvent): void => {
if (!isWideTab) {
setWideTab(!isWideTab);
}
const newTabState = { ...tabState };
const activeTab = event.currentTarget.id;
for (let key in newTabState) {
key === activeTab
? (newTabState[key as keyof typeof newTabState] = true)
: (newTabState[key as keyof typeof newTabState] = false);
}
setTabState(newTabState);
};
Type '{ tabHome: boolean; tabBookmark: boolean; tabEtc: boolean; }' cannot be used as an index type. TS2538
객체를 갖고 노는 for ..in 문 작성 시 나타났던 에러다.
for (let key in newTabState) {
key === activeTab
? (newTabState[key as keyof typeof newTabState] = true)
: (newTabState[key as keyof typeof newTabState] = false);
}
2번 에러와 같은 코드 블럭 내의 에러였고 key를 객체(newTabState)의 keyof typeof로 정의하여 키의 값을 받아와 해결.
참고 자료
const handleSlide = (pixel: any) => {
selectorRef?.current?.scrollTo({
left: selectorRef?.current?.scrollLeft + pixel,
behavior: 'smooth',
});
};
null과 undefined 처리를 해주어야 하는 상황. 옵셔널 체이닝으로 디버깅 완료.
참고 자료1
참고 자료2
TypeScript로 useState작성 시에 const selectorRef = useRef(null);
라고만 작성해도 무방하다. 굳이 const selectorRef = useRef<타입>(null);
타입을 작성하지 않아도 되는 이유는 알아서 타입을 유추하기 때문이다.
다만 ref가 null일 수도 있는 상황에서는 반드시 Generics를 사용해서 표기해주어야 한다.
const selectorRef = useRef<HTMLDivElement>(null);
타입스크립트로 리액트 Hooks 사용하기 (useState, useReducer, useRef)
node_modules를 지워봐도... VSCode를 껐다가 켜는 원시적인 방법을 사용했지만 해결되지 않았던 에러다.
먼저 command + shift + p를 누르고 TypeScript라고 치면 다음과 같은 창이 뜬다. Select a TypeScript Version..을 클릭.
TypeScript version을 4.1.2로 바꾸어 주면 해결!
이상 ... 자바스크립트로 쓰인 리액트 프로젝트를 타입스크립트로 변환하는 좌충우돌 우왕좌왕 후기였다.
솔직히 나중에 진이 빠져서 any를 남발한 경향이 조금 있긴 하지만😇, 앞으로의 리팩토링을 거쳐서 빈틈 없는 타입 정의로 디버깅이 필요없는 튼튼한 프로젝트를 만들고싶다!💪
그렇다면 앞으로도 let's fall in love with coding...💋
퀸은정과 함께여서 그나마 4시반에 끝난것 같습니다.... 정말 고생많으셨어여.... 그와중에 TIL까지.... 지존 짱... 머싯써...