TypeScript 마이그레이션 시작하며 정리한 타입 기초

배경

회사 프로젝트에서 런타임 에러가 잦아 TypeScript 도입을 결정했다. 한 번에 전환하기보다 allowJs 옵션으로 점진적 마이그레이션을 시작했다.

tsconfig.json 설정

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "lib": ["es2017", "dom"],
    "allowJs": true,
    "checkJs": false,
    "jsx": "react",
    "strict": false,
    "esModuleInterop": true
  }
}

처음엔 strict: false로 시작해 점진적으로 타입을 추가하기로 했다.

자주 사용한 패턴

API 응답 타입

interface User {
  id: number;
  name: string;
  email: string;
  createdAt: string;
}

interface ApiResponse<T> {
  data: T;
  status: number;
  message?: string;
}

const getUser = async (id: number): Promise<ApiResponse<User>> => {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
};

제네릭으로 API 응답을 타입화하니 재사용성이 좋았다.

Union 타입으로 상태 관리

type LoadingState = 'idle' | 'loading' | 'success' | 'error';

interface State {
  status: LoadingState;
  data: User | null;
  error: Error | null;
}

문자열 리터럴 유니온 타입으로 상태값을 제한해 오타 실수를 방지할 수 있었다.

Optional과 Partial

interface UpdateUserParams {
  name?: string;
  email?: string;
}

// 또는
type UpdateUserParams = Partial<User>;

PATCH API 파라미터에는 Partial<T>가 유용했다.

마이그레이션 순서

  1. 유틸리티 함수부터 .ts로 변경
  2. API 클라이언트 레이어 타입 추가
  3. React 컴포넌트를 .tsx로 전환
  4. Redux 액션/리듀서 타입 정의

아직 any를 많이 쓰고 있지만, 점진적으로 개선할 예정이다. 타입 추론 덕분에 IDE 자동완성이 향상돼 생산성은 이미 체감된다.

TypeScript 마이그레이션 시작하며 정리한 타입 기초