본문 바로가기
카테고리 없음

타입스크립트 프로젝트 구조 설계 가이드

by JinBytes 2025. 7. 10.

TypeScript 구조 설계를 이미지화 하였다.

 

 타입스크립트는 자바스크립트의 단점을 보완하기 위해 등장한 정적 타입 기반 언어입니다. 자바스크립트와 호환되며 강력한 타입 시스템을 제공해 대규모 애플리케이션 개발 시 안정성과 가독성을 높여주는 장점이 있습니다. 하지만 타입스크립트를 도입한다고 해서 모든 문제가 자동으로 해결되는 것은 아닙니다. 실무에서는 코드 품질뿐 아니라, 프로젝트의 구조 자체가 효율성과 유지보수성에 큰 영향을 미치기 때문입니다.

 

 본 글에서는 타입스크립트 프로젝트를 어떻게 구조화하고 설계하면 실무에서 효과적일지에 대해 구체적으로 안내합니다. 프런트엔드, 백엔드, 전체 스택을 막론하고 공통적으로 적용 가능한 전략을 중심으로 소개합니다.

모듈화 된 디렉터리 구조 설계

 타입스크립트 프로젝트를 체계적으로 설계하려면 먼저 디렉터리 구조를 어떻게 구성할 것인지부터 결정해야 합니다. 특히 프로젝트가 커질수록 모듈화 된 구조를 갖추는 것이 중요합니다. 모듈화란 기능, 역할, 책임 단위로 폴더와 파일을 나누는 전략입니다.

 가장 많이 사용되는 기본 구조는 다음과 같습니다:

src/
├── common/           # 공통 모듈 (에러처리, 응답 포맷 등)
├── config/           # 환경설정 관련
├── controllers/      # 라우터 처리 담당
├── services/         # 비즈니스 로직
├── models/           # 데이터 모델 및 DB 처리
├── interfaces/       # 인터페이스 및 타입 정의
├── dtos/             # 요청 및 응답 스펙 정의
├── utils/            # 유틸 함수 모음
├── middlewares/      # 미들웨어 로직
└── main.ts           # 엔트리 포인트

 

 이 구조는 백엔드(Node.js, NestJS)든 프론트엔드(React, Next.js)든 동일하게 적용할 수 있으며, 규모에 따라 하위 폴더를 기능별로 나누는 것도 좋습니다. 예를 들어 `src/features/users` 폴더 아래에 `user.controller.ts`, `user.service.ts`, `user.dto.ts`를 함께 배치하면 하나의 기능을 중심으로 모든 요소가 모이므로 유지보수와 테스트가 훨씬 수월합니다.

 또한 폴더 및 파일 네이밍 컨벤션도 중요합니다. 일반적으로는 camelCase 또는 kebab-case 중 하나로 일관성을 유지하고, 각 모듈의 `index.ts` 파일을 통해 내부 요소를 export 하여 외부 접근 시 경로를 단순화할 수 있습니다.

TSConfig와 절대경로 설정

 프로젝트가 커질수록 상대 경로를 계속 사용하는 것은 유지보수에 불리합니다. 예를 들어 `import { getUser } from '../../../../services/users'`와 같은 코드는 한눈에 어떤 모듈인지 파악하기 어렵고, 디렉터리 구조가 바뀌면 수많은 경로를 일일이 수정해야 합니다.

이런 문제를 해결하기 위해 `tsconfig.json`의 `paths` 옵션을 활용한 절대 경로 설정이 필수입니다. 다음과 같은 설정 예제를 살펴보겠습니다:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@controllers/*": ["controllers/*"],
      "@services/*": ["services/*"],
      "@models/*": ["models/*"],
      "@utils/*": ["utils/*"],
      "@config/*": ["config/*"]
    }
  }
}

 

 이렇게 설정하면 `import { UserService } from '@services/users'` 와 같이 간단하고 직관적인 경로를 사용할 수 있습니다. 실제로 많은 기업들이 `@` prefix를 붙여 루트 디렉토리를 지정하고 있습니다. 절대 경로 설정은 개발 생산성을 높이는 것뿐 아니라 코드리딩, 협업, 리팩토링을 훨씬 쉽게 만들어 줍니다.

 또한 `tsconfig`에서 반드시 챙겨야 할 옵션은 다음과 같습니다:

  • "strict": true – 타입 안정성을 극대화
  • "esModuleInterop": true – 모듈 호환성 확보
  • "resolveJsonModule": true – JSON 파일 import 가능
  • "noImplicitAny": true – 암시적 any 타입 방지

 이 외에도 컴파일 결과물을 관리하기 위한 `outDir`, `rootDir`, `include`, `exclude` 옵션은 CI/CD 연동 시에도 큰 도움이 됩니다.

 예를 들어 `src`는 개발용, `dist`는 빌드용으로 분리하고 Git에선 `dist`를 무시하도록 `.gitignore`에 명시해야 합니다.

의존성 관리 및 공통 모듈 분리 전략

 구조 설계의 완성은 의존성 설계에 달려 있습니다. 각 기능 모듈이 서로 과도하게 의존하지 않도록 느슨한 결합을 지향해야 하고, 공통 코드나 중복되는 코드는 반드시 분리하여 재사용할 수 있도록 해야 합니다.

 예를 들어 다음과 같은 디렉토리 구분은 많은 기업에서 공통적으로 사용됩니다:

  • src/utils: 로깅, 날짜 포맷, 암호화 등 유틸 함수
  • src/constants: 앱 전역에서 사용하는 상수값
  • src/types: 글로벌 인터페이스 및 타입
  • src/common: 에러 처리, API 응답 포맷 처리

 이렇게 분리하면 특정 모듈에만 종속되지 않으므로 코드 재사용성과 유지보수성이 크게 향상됩니다. 또한 의존성 주입(Dependency Injection) 패턴을 적극 활용하면 각 모듈이 직접 서로를 참조하지 않고도 유기적으로 연결될 수 있습니다.

 예를 들어 NestJS 같은 프레임워크는 DI 패턴을 내장하고 있으며, 모듈 단위로 서비스를 주입받아 테스트 용이성과 확장성을 확보할 수 있습니다. 이와 함께 단위 테스트를 고려한 설계를 하려면 각 서비스의 인터페이스를 먼저 정의하고 구현체는 별도로 나누는 방식이 좋습니다.

 마지막으로 코드 스타일 통일도 중요한 설계 요소입니다. 아래 도구들은 팀의 코드 품질과 협업 생산성을 크게 높여줍니다:

  • ESLint: 문법 및 코드 규칙 검사
  • Prettier: 코드 포맷 자동 정리
  • Husky + lint-staged: 커밋 전 자동 검사
  • Commitlint: 커밋 메시지 형식 강제

 이런 도구를 설정해두면 실수로 잘못된 코드가 커밋되는 것을 방지하고, 누구나 동일한 구조와 컨벤션을 따르게 되어 유지보수 비용이 줄어듭니다. 장기적으로 봤을 때 구조 설계 못지않게 중요한 요소입니다.

 

 요약하자면, 코드 구조를 잘 설계하는 것은 단지 폴더를 나누는 것을 넘어서서 전체 개발 흐름과 협업 문화에 영향을 주는 중요한 작업입니다. 초기부터 잘 설계된 구조는 팀의 생산성과 프로젝트의 성공을 좌우할 수 있습니다.

 

 타입스크립트의 강점을 극대화하려면 단순히 문법을 익히는 데 그치지 않고, 구조 설계 단계부터 체계적으로 접근해야 합니다. 디렉터리 구성, tsconfig 설정, 의존성 관리, 도구 세팅까지 세심하게 설계하면 개발 생산성과 유지보수 효율성이 크게 향상됩니다. 지금 바로 여러분의 프로젝트에 이 구조를 도입해 보세요!