iBetter Books
수정

Ch 04. 실무 마이그레이션 체크리스트

개인 프로젝트와 팀 프로젝트의 마이그레이션은 다릅니다. 혼자 하는 작업은 내가 결정하면 됩니다. 하지만 팀에서는 합의가 필요하고, 자동화가 필요하고, 기록이 필요합니다.

이번 챕터는 실무에서 실제로 필요한 것들을 체크리스트로 정리합니다.

시작 전 팀 합의 사항

마이그레이션을 시작하기 전에 팀이 동의해야 하는 항목들입니다.

전환 목표와 완료 기준. "TypeScript로 전환한다"는 선언만으로는 부족합니다. "언제까지", "어느 수준까지"를 정해야 합니다.

목표 예시:
- 3개월 내에 모든 .js → .ts 전환 완료
- 6개월 내에 noImplicitAny, strictNullChecks 적용
- 1년 내에 strict: true 달성

학습 시간 확보. TypeScript를 모르는 팀원이 있다면, 배우는 시간 없이 마이그레이션을 강행하면 안 됩니다. 1~2주의 학습 스프린트나 코드 리뷰를 통한 멘토링 시간을 계획에 넣습니다.

코딩 컨벤션. 팀 내에서 TypeScript 스타일을 통일합니다. 아래 항목들은 사전에 정해두어야 분쟁을 막을 수 있습니다.

체크 항목:
□ interface vs type alias 언제 쓰는가
□ any 사용 허용 조건 (전혀 금지? 임시 허용?)
□ 타입 단언(as) 사용 규칙
□ 파일명 컨벤션 (PascalCase.ts? camelCase.ts?)
□ export 방식 (named export vs default export)

마이그레이션 PR 규칙. 전환 PR은 리뷰하기 어렵습니다. 파일 하나를 .ts로 바꾸면 import 경로, 타입 추가, 함수 시그니처 변경이 모두 섞입니다. 팀이 합의한 규칙이 없으면 리뷰어가 지칩니다.

권장 규칙:
□ 전환 PR은 비즈니스 로직 변경을 포함하지 않는다
□ 하나의 PR에 최대 N개 파일만 전환한다
□ 전환 PR에는 "migration" 레이블을 붙인다
□ any 타입이 있으면 주석으로 이유를 명시한다

CI 연동

마이그레이션이 진행 중인 동안 CI(Continuous Integration) 파이프라인을 어떻게 설정하느냐가 중요합니다.

타입 검사를 CI에 포함.

# 새 파일: .github/workflows/typecheck.ymlname: Type Checkon:  push:    branches: [main, develop]  pull_request:    branches: [main, develop]jobs:  typecheck:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with:          node-version: '20'          cache: 'npm'      - run: npm ci      - run: npx tsc --noEmit

--noEmit 옵션은 파일을 만들지 않고 타입 검사만 합니다. 빠르고 CI에서 쓰기 좋습니다.

점진적 strict 적용 중에는 별도 검사 추가.

엄격 모드 옵션을 하나씩 켤 때, 해당 옵션만 테스트하는 임시 tsconfig를 만들어두면 편합니다.

// 새 파일: tsconfig.strict-check.json{  "extends": "./tsconfig.json",  "compilerOptions": {    "noImplicitAny": true,    "strictNullChecks": true,    "strictFunctionTypes": true  }}
# 이 명령으로 strict 상태에서 에러 목록 확인npx tsc --noEmit -p tsconfig.strict-check.json

ESLint TypeScript 플러그인 추가.

타입 검사와 별도로 코드 스타일을 자동으로 검사합니다.

npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin
// 새 파일: eslint.config.jsimport tseslint from '@typescript-eslint/eslint-plugin';import tsParser from '@typescript-eslint/parser';export default [  {    files: ['**/*.ts'],    languageOptions: {      parser: tsParser,    },    plugins: {      '@typescript-eslint': tseslint,    },    rules: {      '@typescript-eslint/no-explicit-any': 'warn',      '@typescript-eslint/no-unused-vars': 'error',      '@typescript-eslint/explicit-function-return-type': 'off',    },  },];

코드 리뷰 포인트

TypeScript 전환 PR을 리뷰할 때 체크해야 할 항목입니다.

any 사용 여부. any 타입은 TypeScript를 쓰는 이유를 없애버립니다. 리뷰에서 반드시 확인합니다.

// 리뷰에서 주목해야 하는 패턴function process(data: any): any  // ❌ 이유 없는 anyfunction process(data: unknown): unknown  // ✅ unknown으로 변경 검토function process<T extends DataItem>(data: T): T  // ✅ 제네릭으로 변경

타입 단언(as) 남용. as는 TypeScript에게 "내가 더 잘 안다"고 선언하는 것입니다. 필요한 경우가 있지만, 남용하면 안전성이 사라집니다.

// 리뷰에서 확인할 사항const user = data as User;  // 실제로 User 타입인지 확인했는가?// 더 나은 패턴if (isUser(data)) {  // 타입 가드로 확인 후 사용  const user = data;  // 여기서 user는 안전하게 User 타입}

null 처리 누락. strictNullChecks를 켠 상태에서도 컴파일러를 속이는 패턴이 있습니다.

// 위험한 패턴: 비어 있을 수 있는 배열의 첫 번째 요소const firstUser = users[0];  // undefined일 수 있습니다console.log(firstUser.name);  // 런타임 에러 가능// 안전한 패턴const firstUser = users.at(0);  // undefined | Userif (firstUser) {  console.log(firstUser.name);}

성공 사례와 실패 사례

실제 마이그레이션 프로젝트에서 공통적으로 관찰되는 패턴을 정리합니다.

성공 패턴.

타입 정의 파일(types.ts, interfaces.ts)을 가장 먼저 만든 팀은 전환 속도가 빠릅니다. 모든 팀원이 같은 데이터 구조를 보고 작업할 수 있기 때문입니다.

"완벽한 타입"을 고집하지 않은 팀이 성공률이 높습니다. 초기에는 any를 허용하고 점진적으로 개선하는 팀이, 처음부터 완벽을 추구하다 지쳐버린 팀보다 결과가 좋습니다.

코드 리뷰를 통해 TypeScript 지식이 자연스럽게 전파된 팀은 외부 교육 없이도 팀 전체의 TypeScript 역량이 올라갑니다.

실패 패턴.

"한 번에 다 바꾸자"는 접근은 대부분 실패합니다. 두 달에 걸쳐 대규모 PR을 만들었는데 리뷰도 못 하고 코드가 다 바뀌어서 병합 충돌이 생기는 경우를 자주 봅니다.

TypeScript 전환 브랜치를 오래 유지하면 안 됩니다. main 브랜치가 계속 바뀌는 동안 전환 브랜치만 따로 있으면 병합할 때 지옥을 경험합니다. 작은 단위로 자주 병합하는 것이 맞습니다.

tsconfig.json 설정을 너무 빨리 엄격하게 가져가도 문제입니다. 팀원들이 빌드조차 안 되는 상황을 경험하면 TypeScript 자체에 반감을 가질 수 있습니다.

마이그레이션 완료 체크리스트

착수 전
□ 팀 전체가 마이그레이션 목표와 일정에 동의했는가
□ TypeScript 기초 학습 계획이 있는가
□ tsconfig.json 초기 설정을 완료했는가
□ allowJs: true로 공존 환경을 구성했는가

진행 중
□ 타입 정의 파일(types.ts)을 먼저 만들었는가
□ 의존성이 적은 파일부터 전환하고 있는가
□ PR 크기를 작게 유지하고 있는가 (파일 5개 이하 권장)
□ any 사용 시 주석으로 이유를 남기고 있는가
□ CI에서 타입 검사를 자동으로 실행하고 있는가
□ 코드 리뷰에서 타입 관련 피드백을 주고받고 있는가

완료 후
□ 모든 .js 파일이 .ts로 전환되었는가
□ noImplicitAny가 적용되었는가
□ strictNullChecks가 적용되었는가
□ ESLint TypeScript 플러그인이 설정되었는가
□ 팀 내 TypeScript 코딩 컨벤션 문서가 있는가
□ 후속 strict 옵션 적용 일정이 잡혔는가

마이그레이션은 끝이 있는 프로젝트입니다. 하지만 TypeScript를 잘 쓰는 것은 계속되는 여정입니다. 전환이 완료된 후에도 타입을 개선하고, strict를 높여가고, 새로운 TypeScript 기능을 활용하는 작업은 계속됩니다.

PART 09가 끝났습니다. 이제 마지막 PART에서 TypeScript의 다음을 이야기합니다.