✍️ 기록/React

[React] 기존 React 프로젝트 TypeScript 적용

김물사 2025. 3. 12. 16:13

📌 TypeScript

- TypeScript는 마이크로소프트에서 개발한 JavaScript의 상위 집합(Superset) 언어로, 정적 타입을 지원하고 확장자로 .ts를 사용하며 작성한 코드는 컴파일을 거쳐 JavaScript로 변환됩니다.
- 가장 큰 특징은 정적 타입을 명시할 수 있다는 점. 이를 통해 개발 도구(IDE)와 컴파일러가 코드 자동 완성 타입 오류 감지 등의 피드백을 제공하여 생산성을 높이고 버그를 줄이며 유지보수를 쉽게 만듭니다. 👍
즉, TypeScript는 실행 전에 타입 오류를 미리 잡아주는 역할을 하는 언어 !

 

📍 기존 React 프로젝트에 TypeScript 설치

npm i typescript @types/node @types/react @types/react-dom @types/jest

 

✅ typescript

- TypeScript의 컴파일러(tsc)를 포함한 핵심 패키지

- .ts나 .tsx 파일을 JavaScript로 변환하는 역할

 

✅ @types/node

- Node.js에서 TypeScript를 사용할 때 필요한 타입 정의

- TypeScript 프로젝트에서 Node.js의 내장 모듈(예: fs, path, http 등)을 사용할 때 해당 모듈의 타입 정보를 자동으로 가져올 수 있게 해줍니다.

 

✅ @types/react

- React 관련 타입 정의

- React의 컴포넌트, 훅, 이벤트 등에서 TypeScript를 사용할 수 있도록 해줌

 

✅ @types/react-dom

- react-dom의 타입 정의 파일

- ReactDOM.render() 같은 함수에서 TypeScript를 사용할 수 있도록 도와줍니

✅ @types/jest

- Jest(테스트 프레임워크) 관련 타입 정의

- Jest를 사용할 때 TypeScript의 지원을 받으려면 필요

※ 만약 Jest를 사용하지 않는다면 설치하지 않아도 돼요 

 

📍 tsconfig.json 파일 생성

- TypeScript를 설정하려면 프로젝트 루트에 tsconfig.json 파일을 추가 해야 하는데

tsc --init 명령어를 실행하여 기본 설정 파일을 생성 

- tsconfig.json 파일을 통해 TypeScript 컴파일러의 기본 설정을 포함하고 있고 컴퍼일러 옵션을 설정 !

 

npx tsc --init

☝️ 파일 생성 확인

 

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES6",
    "module": "esnext",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": [
    "src"
  ]
}

 

target: "ES6"

- 컴파일된 코드가 사용할 JavaScript 버전을 ES6으로 설정

 

module: "esnext"

- 모듈 시스템을 최신 ES 모듈로 설정

-  최신 JavaScript(ES6+)에서 사용하는 import/export 구문을 그대로 사용할 수 있습니다.

 

lib : ["dom", "dom.iterable", "esnext"]

- 사용할 라이브러리의 종류를 설정합니다.

- DOM API, DOM 이터러블 API, ESNext(최신 ECMAScript 표준)포함.

- React 프로젝트에서는 dom이 필수적이며, 최신 기능을 사용하려면 esnext를 포함하는 것이 좋습니다.

 

  moduleResolution: "node"

- 모듈을 Node.js 방식으로 해석하도록 설정합니다. node_modules에서 모듈을 찾을 때 Node.js의 모듈 해석 규칙을 따릅니다.

 

✅ resolveJsonModule

- .json 파일을 모듈처럼 import할 수 있게 허용

- JSON 파일을 TypeScript에서 직접 import하려는 경우 유용

 

 jsx: "react-jsx"

- react-jsx는 JSX를 컴파일할 때 React.createElement 호출을 자동으로 처리합니다.

 

✅  strict

- TypeScript의 엄격한 타입 검사를 활성화합니다.

- 코드 품질을 높이고, 오류를 미리 잡아낼 수 있도록 도와줍니다.

 

✅  esModuleInterop

- CommonJS와 ES 모듈 간의 호환성을 개선하는 옵션

- require와 import를 함께 사용할 때 발생하는 문제를 해결합니다

 

✅ allowJs

- 기존 JavaScript 파일도 TypeScript 프로젝트 내에서 사용할 수 있게 허용합니다.

- JavaScript에서 TypeScript로 전환하는 중에 유용합니다.

- avaScript와 TypeScript를 함께 사용하려는 경우 설정

 

✅ allowSyntheticDefaultImports

- ES 모듈에서 default export를 사용할 때, CommonJS 모듈의 module.exports를 default로 처리할 수 있게 해줍니다.

 

skipLibCheck

- 라이브러리의 타입 정의 파일에 대한 검사를 건너뛰도록 설정합니다.

- 외부 라이브러리의 타입 정의 오류를 무시, 타입 정의에 문제가 있어도 컴파일 오류를 피할 수 있게 해 줍니다.

 

✅ forceConsistentCasingInFileNames

- 파일 이름의 대소문자 일관성을 강제합니다. 예를 들어, MyComponent.tsx와 myComponent.tsx가 다른 파일로 처리

- 운영 체제에 따라 대소문자 구분이 다를 수 있기 때문에 대소문자 일관성을 유지하기 위해 사용됩니다.

 

✅ noFallthroughCasesInSwitch

- switch 문에서 fall-through(케이스 간에 break 없이 실행되는 현상)을 방지하도록 설정

- switch 문을 사용할 때 의도하지 않은 동작을 방지하여 코드 안정성을 높입니다.

 

✅isolatedModules

- 각 파일을 독립적으로 처리할 수 있도록 설정

- 주로 Babel과 함께 사용할 때 필요하며, jsx가 있는 파일에서도 사용됩니다.

- 파일 별로 독립적인 컴파일을 위해 설정됩니다.

 

✅ noEmit

- TypeScript 컴파일러가 JavaScript 파일을 생성하지 않도록 설정

- 타입 검사만 수행하고 JavaScript 파일을 출력하지 않게 합니다.

- 타입 체크만 하고, 컴파일된 JavaScript 파일을 생성하고 싶지 않을 때 사용됩니다.

 

✅ "include": ["src"]

- src 폴더 안에 있는 모든 TypeScript 파일을 검사하고 컴파일 진행

- src 폴더가 프로젝트의 주요 코드가 있는 디렉토리일 때 적합합니다 

- 외부 타입 선언 파일이나 특정 파일을 포함시키려면 별도로 include 항목을 추가 필요합니다

 

📍 파일 확장자 변경

- TypeScript 로 진행하기 위해서는 .js 파일은 .ts로 .jsx 파일은 .tsx로 확장자로 변경

- 컴포넌트가 포함된 파일은 .tsx  확장자로 변경

- 일반적인 JavaScript 파일은 .ts로 변경

 

EX) 

src/App.js ➡️  src/App.tsx

src/pages/MainPage.jsx ➡️  src/pages/MainPage.tsx

src/utils/test.js   ➡️  src/utils/test.ts

 

😅 파일 수가 엄청 많은 상태에서 진행하는 경우 힘들 수 있어요!

 

📍경로 별칭

✅ 타입스크립트를 적용하기 전 경로 별칭을 사용해서 import를 하고 있었는데

타입스크립트를 적용하면서 다시 해야하는 문제 발생!!

 

jsconfig.json 파일은 삭제 하고  tsconfig.json 옵션 추가 진행

// tsconfig.json
{
  "compilerOptions": {
    ...,
    "baseUrl": "./src",
    "paths": {
      "*": ["*"]
    }
  },
  
}

 

- baseUrl / paths 추가

 

📍index.tsx 에러

index.js ➡️ index.tsx 변경 후 발생하는 에러

Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Container'.
Type 'null' is not assignable to type 'Container'.ts(2345)

 

✅ document.getElementById('root')가 null을 반환할 수 있기 때문에 발생.

 

📗 해결방법

✅ ! (Non-null assertion operator) 사용

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

- null, undefined가 아니라고 단언

 

✅ if문으로 null 체크

const rootElement = document.getElementById('root');

if (rootElement) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  );
}

- rootElement가 null인지 if문으로 확인 후 root.render() 호출.

- null 일경우 else console.error를 사용하여 오류를 확인 하여 디버깅, 처리 가능

 

✅ as HTMLElement

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

- document.getElementById('root')의 반환 타입은 HTMLElement | null인데, as HTMLElement를 사용하면 무조건 HTMLElement로 간주

- 문제 강제로 HTMLElement로 간주하기 때문에 런타임 오류가 발생할 수 있습니다.

 

- 짧고 간결하면서 사용하기 위해서는 ! (Non-null assertion) 사용, 가장 안전한 방법으로 if문 사용

 

📍Router createBrowserRouter element  에러

- 'App' refers to a value, but is being used as a type here. Did you mean 'typeof App'?ts(2749)

- TypeScript 별칭 설정을 잘못했을까 하고 수정도 하고 App.tsx 수정도 했지만 에러나와 찾아보니 파일 확장자 문제..😅

 

🔽 .ts → .tsx

✅ element에서 컴포넌트를 전달하면서 JSX 포함하고 있지만 .ts는 JSX를 인식하지 못하기 때문에 오류 발생..!

확장자를 .tsx를 변경하여 오류 해결

 

🔗 확장자 해결 - 참고 velog

 

확장자 변경과 발생하는 오류를 해결을 하고 나면 끝!

 

 

✅ 완료! 

 

 

 

✍️ 기록

 

감사합니다. 😁

반응형