기존 Express 프로젝트에 TypeScript 점진적으로 도입하기

배경

6개월간 운영 중인 Express API 서버가 있었다. JavaScript로 작성되어 있었고, 팀원이 늘면서 런타임 에러가 잦아졌다. 특히 req.body의 속성을 잘못 접근하거나, 함수 파라미터 타입이 맞지 않는 경우가 많았다.

전체를 한 번에 TypeScript로 마이그레이션하기엔 리스크가 컸다. 점진적 도입 전략을 선택했다.

도입 과정

1. 설정 파일 추가

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2017",
    "module": "commonjs",
    "lib": ["es2017"],
    "allowJs": true,
    "checkJs": false,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

allowJs: true 옵션으로 JS와 TS 파일을 함께 사용할 수 있게 했다.

2. 새 코드부터 TS 적용

새로 추가하는 라우터와 미들웨어는 .ts 확장자로 작성했다.

// src/routes/users.ts
import { Router, Request, Response } from 'express';
import { UserService } from '../services/user.service';

const router = Router();

interface CreateUserRequest {
  email: string;
  password: string;
  name: string;
}

router.post('/users', async (req: Request, res: Response) => {
  const body = req.body as CreateUserRequest;
  
  if (!body.email || !body.password) {
    return res.status(400).json({ error: 'Invalid request' });
  }
  
  const user = await UserService.create(body);
  res.json(user);
});

export default router;

3. 자주 수정하는 파일 우선 전환

비즈니스 로직이 자주 변경되는 파일부터 .js.ts로 변경했다. 타입 에러를 하나씩 해결하며 실제 버그를 여럿 발견했다.

효과

  • 새 기능 개발 시 타입 체크로 실수 방지
  • IDE 자동완성이 정확해져 생산성 향상
  • PR 리뷰에서 타입 관련 논의 감소

2주간 약 30% 정도의 코드를 TypeScript로 전환했다. 나머지는 천천히 마이그레이션할 계획이다.

기존 Express 프로젝트에 TypeScript 점진적으로 도입하기