[TYPESCRIPT] React + TypeScript 프로젝트 시작하기 — 실무에서 바로 쓰는 기본 세팅

 

React 프로젝트를 TypeScript로 시작하는 것은 이제 선택이 아니라 기본에 가깝습니다. 컴포넌트의 Props, 상태(State), 이벤트, API 응답까지 모든 흐름을 타입으로 고정할 수 있기 때문에 규모가 커질수록 유지보수성과 안정성 차이가 크게 벌어집니다.

React + TypeScript 프로젝트를 처음 시작할 때 가장 많이 쓰이는 방식과 실무 기준 설정 포인트를 정리합니다.

 

React + TypeScript를 쓰는 이유

React에서 TypeScript를 사용하는 가장 큰 이유는 다음과 같습니다.

  • Props 타입이 명확해 컴포넌트 사용 실수 감소
  • 상태 구조가 커져도 안정적으로 관리 가능
  • 리팩토링 시 컴파일 단계에서 오류 감지
  • IDE 자동완성 및 탐색성 대폭 향상

특히 팀 단위 개발이나 중·대형 프로젝트에서는 TypeScript 없는 React는 거의 관리가 불가능해집니다.

 

프로젝트 생성 (Vite 기준)

최근 실무에서는 Vite + React + TypeScript 조합이 가장 많이 사용됩니다.

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev

이 방식의 장점은 다음과 같습니다.

  • 빠른 개발 서버
  • 불필요한 설정 최소화
  • TypeScript 기본 세팅 포함

 

기본 폴더 구조 이해하기

생성된 프로젝트의 핵심 구조는 다음과 같습니다.

src/
  main.tsx
  App.tsx
  vite-env.d.ts
  • main.tsx : React 진입점
  • App.tsx : 최상위 컴포넌트
  • vite-env.d.ts : Vite 전용 타입 정의

React + TypeScript 프로젝트에서는 .tsx 확장자가 JSX + TypeScript를 의미합니다.

 

첫 컴포넌트와 타입 기본

가장 기본적인 함수형 컴포넌트는 다음과 같습니다.

function App() {
  return <h1>Hello React + TypeScript</h1>;
}

export default App;

TypeScript에서는 컴포넌트 반환 타입을 굳이 명시하지 않아도 JSX.Element로 자동 추론됩니다.

 

Props 타입 정의하기

React + TypeScript의 핵심은 Props 타입입니다.

type GreetingProps = {
  name: string;
  age?: number;
};

function Greeting({ name, age }: GreetingProps) {
  return (
    <div>
      Hello {name} {age && `(age: ${age})`}
    </div>
  );
}

이제 컴포넌트 사용 시 타입이 강제됩니다.

<Greeting name="Alice" />      // OK
<Greeting />                   // X name 누락

Props 타입 정의만으로도 컴포넌트 사용 실수를 대폭 줄일 수 있습니다.

 

useState와 타입

useState는 대부분 타입 추론으로 충분합니다.

const [count, setCount] = useState(0);
// count: number

다만, 초기값이 null인 경우에는 명시가 필요합니다.

const [user, setUser] = useState<User | null>(null);

이 패턴은 API 데이터 로딩 시 매우 자주 사용됩니다.

 

이벤트 핸들러 타입

React 이벤트는 DOM 이벤트와 타입이 다릅니다.

function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
  console.log(e.target.value);
}

자주 쓰이는 이벤트 타입은 다음과 같습니다.

  • ChangeEvent<HTMLInputElement>
  • MouseEvent<HTMLButtonElement>
  • FormEvent<HTMLFormElement>

 

API 데이터와 타입 연동

React + TypeScript에서는 API 응답 타입을 반드시 정의합니다.

type User = {
  id: number;
  name: string;
};

const [users, setUsers] = useState<User[]>([]);

이렇게 하면 렌더링 시점에서 잘못된 접근을 막을 수 있습니다.

users.map(u => u.name); // 안전

앞서 다룬 타입 안전한 API 응답 패턴과 함께 쓰면 가장 이상적입니다.

 

tsconfig.json에서 꼭 확인할 옵션

Vite 템플릿의 기본 tsconfig는 꽤 잘 되어 있지만, 아래 옵션은 반드시 확인하는 것을 권장합니다.

{
  "compilerOptions": {
    "strict": true,
    "jsx": "react-jsx",
    "noImplicitAny": true
  }
}

strict 모드는 React + TypeScript에서 사실상 필수입니다.

 

실무에서 바로 추가하는 것들

프로젝트 시작 후 보통 아래 요소들을 빠르게 추가합니다.

  • 라우팅 : react-router + 타입 안전한 params
  • API 통신 : Axios + 제네릭
  • 상태 관리 : React Query / Zustand
  • 공통 타입 폴더 (types/)

초기 구조를 잘 잡아두면 이후 확장이 훨씬 수월해집니다.

 


 

React + TypeScript 프로젝트의 핵심은 컴포넌트, 상태, API를 모두 “타입 계약”으로 묶는 것입니다. 초반에 타입 설계를 잘 해두면, 프로젝트가 커질수록 그 효과가 눈에 띄게 나타납니다.

  • 컴포넌트 Props는 반드시 타입으로
  • 상태와 API 응답 구조를 명확히
  • strict 모드는 기본값