React

[React] 기존 React 프로젝트에 TypeScript 설치하기

dud9902 2025. 1. 15. 21:28

멘토님께서 React 사용하면서 TypeScript를 꼭 사용하라고 하셔서 세팅한 과정을 정리해봤다.

 

사실 리액트 프로젝트를 생성할때 타입스크립트로 설치해야 더 좋은것 같다.

하지만 나는 그 사실을 몰랐다.. 중간에 설치하면 바로 되는줄 알았다....

기존 프로젝트에 설치 할 경우 오류가 뜬다고 적혀있던 글들이 많았다. (나도 뜸)

 

처음에는 이 명령어를 실행했다.

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

 

그리고 설치된 패키지 확인을 위해 다시 확인했다.

npm list typescript @types/react @types/react-dom

 

그런데 확인하는 과정에서 오류가 떴다.

C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd>npm list typescript @types/react @types/react-dom
travelplaner@0.1.0 C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd
├─┬ @testing-library/react@13.4.0
│ └─┬ @types/react-dom@18.3.5
│   └── @types/react@18.3.18
├─┬ @types/react-dom@19.0.3
│ └── @types/react@19.0.7 deduped
├── @types/react@19.0.7
├─┬ react-scripts@5.0.1
│ ├─┬ eslint-config-react-app@7.0.1
│ │ └─┬ @typescript-eslint/eslint-plugin@5.62.0
│ │   └─┬ tsutils@3.21.0
│ │     └── typescript@5.7.3 deduped invalid: "^3.2.1 || ^4" from node_modules/react-scripts
│ ├─┬ react-dev-utils@12.0.1
│ │ └─┬ fork-ts-checker-webpack-plugin@6.5.3
│ │   └── typescript@5.7.3 deduped invalid: "^3.2.1 || ^4" from node_modules/react-scripts
│ └── typescript@5.7.3 deduped invalid: "^3.2.1 || ^4" from node_modules/react-scripts
├─┬ travelplaner@0.1.0 -> .\
│ ├── @types/react-dom@19.0.3 deduped
│ ├── @types/react@19.0.7 deduped
│ └── typescript@5.7.3 deduped invalid: "^3.2.1 || ^4" from node_modules/react-scripts
└── typescript@5.7.3 invalid: "^3.2.1 || ^4" from node_modules/react-scripts

npm error code ELSPROBLEMS
npm error invalid: typescript@5.7.3 C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd\node_modules\typescript
npm error A complete log of this run can be found in: C:\Users\dud99\AppData\Local\npm-cache\_logs\2025-01-15T12_06_07_264Z-debug-0.log

 

오류 메세지 내용

 TypeScript 설치는 완료되었으나, React Scripts와 호환되지 않는 버전(typescript@5.7.3)으로 인해 문제가 발생한 것으로 보입니다. React Scripts는 특정 TypeScript 버전과 호환되어야 하며, 현재 사용 중인 React Scripts(5.0.1)는 typescript@^4.x와 호환된다.

 

문제 원인

  1. React Scripts 의존성
    React Scripts에서 요구하는 TypeScript 버전(^3.2.1 || ^4)과 설치된 TypeScript 버전(5.7.3)이 맞지 않아 invalid 경고가 발생
  2. TypeScript 버전 충돌
    프로젝트에서 사용하는 TypeScript와 의존성으로 설치된 다른 버전 간의 충돌로 인해 문제가 발생

오류 해결 과정1

그래서 나는 아예 호환되는 버전으로 설치하기 위해서 세팅하던 폴더를 지우고 브랜치에서 다시 파일을 내려받았다.

 

1. 기존 의존성 삭제

  • Window
rd /s /q node_modules
del package-lock.json
  • Max/OS
rm -rf node_modules package-lock.json

 

2. TypeScript와 React Scripts 호환 버전 설치

npm install --save-dev typescript@4.9.5

 

3. 필요한 의존성 재설치

npm install

 

4. 설치 확인

npx tsc --version

 

5. tsconfig.json 파일 생성

npx tsc --init

 

6. React 프로젝트 파일 업데이트
TypeScript를 사용하려면 .js 파일을 .ts 또는 .tsx로 변경한다.

  • .ts: TypeScript 코드를 작성하는 일반 파일
  • .tsx: React 컴포넌트가 포함된 파일

이제 프로젝트를 실행해 문제가 해결되었는지 확인하면 된다!

 


설치가 끝난줄 알았지만 추가 작업이 있다.

 .js, .jsx 파일 형식을 .tsx로 변경해줘야 한다.

 

 폴더에 있는 파일들을 .tsx로 바꿨더니 파일마다 엄청난 오류를 내뱉었다.

ERROR
Module not found: Error: Can't resolve 'C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd\src\index.js' in 'C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd'
ERROR in src/App.test.tsx:2:17
TS6142: Module './App' was resolved to 'C:/Users/dud99/OneDrive/바탕 화면/final_project/travelPlaner_FrontEnd/src/App.tsx', but '--jsx' is not set.
    1 | import { render, screen } from '@testing-library/react';
  > 2 | import App from './App';
      |                 ^^^^^^^
    3 |
    4 | test('renders learn react link', () => {
    5 |   render(<App />);
ERROR in src/App.test.tsx:5:10
TS17004: Cannot use JSX unless the '--jsx' flag is provided.
    3 |
    4 | test('renders learn react link', () => {
  > 5 |   render(<App />);
      |          ^^^^^^^
    6 |   const linkElement = screen.getByText(/learn react/i);
    7 |   expect(linkElement).toBeInTheDocument();
    8 | });

 

오류 해결 과정2

tsconfig.json 파일에서 // "jsx": "preserve", /* Specify what JSX code is generated. */ 주석을 풀고  "jsx": "react-jsx", 로 수정했다.

  •  React 17 이상을 사용하는 경우: "react-jsx"
  • React 16 이하를 사용하는 경우: "react"

 

수정 후 다시 프로젝트를 재실행했지만 또 다시 오류가 발생했다.

ERROR in ./src/App.tsx 8:0-51
Module not found: Error: Can't resolve './components/header/Header.js' in 'C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd\src'
ERROR in ./src/App.tsx 9:0-51
Module not found: Error: Can't resolve './components/footer/Footer.js' in 'C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd\src'
ERROR in src/index.tsx:6:34
TS2345: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Container'.
  Type 'null' is not assignable to type 'Container'.
    4 | import reportWebVitals from './reportWebVitals';
    5 |
  > 6 | const root = ReactDOM.createRoot(document.getElementById('root'));
      |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    7 | root.render(
    8 |   <React.StrictMode>
    9 |     <App />
ERROR in src/index.tsx:16:1
TS2554: Expected 1 arguments, but got 0.
    14 | // to log results (for example: reportWebVitals(console.log))
    15 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
  > 16 | reportWebVitals();
       | ^^^^^^^^^^^^^^^^^
    17 |

 

이번 오류는 여러곳에서 발생했다.

1. 파일의 import부분에서 .js가 포함되었다는 오류

그냥 파일 형식을 지워주기만 하면 된다.

  • 수정 전: import Header from './components/header/Header.js';
  • 수정 : import Header from './components/header/Header';

2. index.tsx 파일에서 ReactDOM.createRoot 관련 오류

ReactDOM.createRoot 메서드는 document.getElementById('root')가 null을 반환할 가능성을 처리하지 않았기 때문에 발생했다.

해결 방법

document.getElementById가 null일 가능성을 제거하거나, TypeScript에서 이를 처리하는 것이다.

수정 전

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

수정 후

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';

const rootElement = document.getElementById('root'); // 'root' 요소 가져오기
if (rootElement) {
  const root = ReactDOM.createRoot(rootElement as HTMLElement); // null이 아님을 명시
  root.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  );
} else {
  console.error('Root element not found.'); // 'root' 요소가 없을 경우 에러 처리
}

// 성능 측정 함수 호출
reportWebVitals();

 

3. reportWebVitals.tsx 관련 오류

reportWebVitals.tsx에서 매개변수의 타입을 명시하지 않아 오류가 발생했다.

 

처음에는 이렇게 수정했었다.

import { ReportHandler } from 'web-vitals';

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

 

하지만 다시 오류가 발생했다.

  • web-vitals 모듈과 관련된 타입 정의 문제 및 메서드 접근 문제로 인해 발생
  • web-vitals 모듈에서 사용 가능한 메서드가 제대로 인식되지 않거나, 최신 버전에서 타입 정의가 변경된 경우
ERROR in src/reportWebVitals.tsx:1:10
TS2305: Module '"web-vitals"' has no exported member 'ReportHandler'.
  > 1 | import { ReportHandler } from 'web-vitals';
      |          ^^^^^^^^^^^^^
    2 |
    3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
    4 |   if (onPerfEntry && onPerfEntry instanceof Function) {
ERROR in src/reportWebVitals.tsx:5:34
TS2339: Property 'getCLS' does not exist on type '{ default: typeof import("C:/Users/dud99/OneDrive/\uBC14\uD0D5 \uD654\uBA74/final_project/travelPlaner_FrontEnd/node_modules/web-vitals/dist/modules/index"); onCLS: (onReport: (metric: CLSMetric) => void, opts?: ReportOpts | undefined) => void; ... 10 more ...; FIDThresholds: MetricRatingThresholds; }'.
    3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
    4 |   if (onPerfEntry && onPerfEntry instanceof Function) {
  > 5 |     import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      |                                  ^^^^^^
    6 |       getCLS(onPerfEntry);
    7 |       getFID(onPerfEntry);
    8 |       getFCP(onPerfEntry);
ERROR in src/reportWebVitals.tsx:5:42
TS2339: Property 'getFID' does not exist on type '{ default: typeof import("C:/Users/dud99/OneDrive/\uBC14\uD0D5 \uD654\uBA74/final_project/travelPlaner_FrontEnd/node_modules/web-vitals/dist/modules/index"); onCLS: (onReport: (metric: CLSMetric) => void, opts?: ReportOpts | undefined) => void; ... 10 more ...; FIDThresholds: MetricRatingThresholds; }'.
    3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
    4 |   if (onPerfEntry && onPerfEntry instanceof Function) {
  > 5 |     import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      |                                          ^^^^^^
    6 |       getCLS(onPerfEntry);
    7 |       getFID(onPerfEntry);
    8 |       getFCP(onPerfEntry);

 

계속 수정해서 고쳤지만 오류가 발생해서 지쳐갈때쯤 AI 친구가 또 다른 해결책을 알려주었다.

npm install --save web-vitals @types/web-vitals

 

하지만 또 다시 오류가 발생했다.

  • @types/web-vitals 패키지가 npm 레지스트리에서 제공되지 않는 상황
  • web-vitals 라이브러리가 자체적으로 타입 정의를 포함하고 있기 때문일 가능성이 높습니다. 따라서 별도로 @types/web-vitals를 설치할 필요는 없음
C:\Users\dud99\OneDrive\바탕 화면\final_project\travelPlaner_FrontEnd>npm install --save web-vitals @types/web-vitals
npm error code E404
npm error 404 Not Found - GET https://registry.npmjs.org/@types%2fweb-vitals - Not found
npm error 404
npm error 404  '@types/web-vitals@*' is not in this registry.
npm error 404
npm error 404 Note that you can also install from a
npm error 404 tarball, folder, http url, or git url.
npm error A complete log of this run can be found in: C:\Users\dud99\AppData\Local\npm-cache\_logs\2025-01-15T12_47_03_584Z-debug-0.log

해결방법

1. web-vitals만 설치하고, 타입 관련 문제는 기존 web-vitals 모듈에서 제공하는 타입을 활용하여 해결

npm install --save web-vitals

 

2. 매개변수 onPerfEntry에 타입을 추가

수정 전

const reportWebVitals = onPerfEntry => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

수정 후

const reportWebVitals = (onPerfEntry?: any) => {
  if (onPerfEntry && typeof onPerfEntry === 'function') {
    import('web-vitals').then(({
      onCLS,
      onFID,
      onFCP,
      onLCP,
      onTTFB
    }) => {
      onCLS(onPerfEntry);
      onFID(onPerfEntry);
      onFCP(onPerfEntry);
      onLCP(onPerfEntry);
      onTTFB(onPerfEntry);
    }).catch(error => {
      console.error('Failed to load web-vitals module:', error);
    });
  }
};

export default reportWebVitals;

 

오류 해결하면서 그냥 프로젝트 삭제하고 타입스크립트로 다시 설치할지 엄청 고민했다.

아무튼 해결해서 햅삐였다.