대규모 TypeScript 프로젝트에서는 체계적인 구조와 일관된 코드 품질이 필수입니다. 모노레포, ESLint/Prettier, 테스트 전략으로 유지보수하기 쉬운 코드베이스를 만드세요.
Large-scale TypeScript projects require systematic structure and consistent code quality. Build a maintainable codebase with monorepos, ESLint/Prettier, and testing strategies.
프로젝트 디렉토리 구조 Project Directory Structure
Feature 기반 구조는 대규모 프로젝트에서 확장성과 유지보수성을 높입니다.
Feature-based structure improves scalability and maintainability in large projects.
# 권장 프로젝트 구조
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ ├── types.ts
│ │ └── index.ts
│ └── users/
├── shared/
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ └── types/
├── lib/
│ ├── api.ts
│ └── config.ts
└── app/
├── layout.tsx
└── page.tsx
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ ├── types.ts
│ │ └── index.ts
│ └── users/
├── shared/
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ └── types/
├── lib/
│ ├── api.ts
│ └── config.ts
└── app/
├── layout.tsx
└── page.tsx
# Recommended project structure
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ ├── types.ts
│ │ └── index.ts
│ └── users/
├── shared/
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ └── types/
├── lib/
│ ├── api.ts
│ └── config.ts
└── app/
├── layout.tsx
└── page.tsx
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ ├── types.ts
│ │ └── index.ts
│ └── users/
├── shared/
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ └── types/
├── lib/
│ ├── api.ts
│ └── config.ts
└── app/
├── layout.tsx
└── page.tsx
tsconfig.json 최적화 Optimizing tsconfig.json
// tsconfig.json - 프로덕션 권장 설정
{
"compilerOptions": {
// 타입 체크 강화
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
// 모듈 설정
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
// 경로 별칭
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@features/*": ["./src/features/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
{
"compilerOptions": {
// 타입 체크 강화
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
// 모듈 설정
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
// 경로 별칭
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@features/*": ["./src/features/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
// tsconfig.json - Production recommended settings
{
"compilerOptions": {
// Strict type checking
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
// Module settings
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
// Path aliases
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@features/*": ["./src/features/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
{
"compilerOptions": {
// Strict type checking
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
// Module settings
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
// Path aliases
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@features/*": ["./src/features/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
ESLint & Prettier 설정 ESLint & Prettier Configuration
// eslint.config.js (Flat Config)
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
}
);
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
}
);
// eslint.config.js (Flat Config)
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
}
);
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
}
);
📦 pnpm 모노레포 설정 📦 pnpm Monorepo Setup
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
# 디렉토리 구조
monorepo/
├── apps/
│ ├── web/ # Next.js 앱
│ └── api/ # NestJS API
├── packages/
│ ├── ui/ # 공유 컴포넌트
│ ├── config/ # ESLint, TS 설정
│ └── utils/ # 공유 유틸리티
└── pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
# 디렉토리 구조
monorepo/
├── apps/
│ ├── web/ # Next.js 앱
│ └── api/ # NestJS API
├── packages/
│ ├── ui/ # 공유 컴포넌트
│ ├── config/ # ESLint, TS 설정
│ └── utils/ # 공유 유틸리티
└── pnpm-workspace.yaml
⚠️ 흔한 실수들 ⚠️ Common Mistakes
any타입 남용으로 타입 안전성 상실- 순환 의존성 (Circular Dependencies)
- 타입 정의와 구현 파일 분리 미흡
- 런타임 vs 컴파일타임 타입 혼동
- Overusing
anytype losing type safety - Circular dependencies
- Poor separation of type definitions and implementation
- Confusion between runtime and compile-time types
💡 타입 안전 팁 💡 Type Safety Tips
unknown을any대신 사용- Type Guards로 런타임 타입 검증
as const로 리터럴 타입 보존- Zod/Valibot으로 런타임 검증과 타입 추론 통합
- Use
unknowninstead ofany - Validate runtime types with Type Guards
- Preserve literal types with
as const - Integrate runtime validation with Zod/Valibot
