JavaScript에서 TypeScript 마이그레이션 — 단계별 전환 전략
JavaScript에서 TypeScript로의 마이그레이션은 한 번에 전환하지 않고 점진적으로 진행하는 것이 안전합니다. 기존 JS 코드와 새 TS 코드를 함께 운영하면서 단계적으로 전환합니다.
전환 전략 개요
1단계: TypeScript 설치 + allowJs
2단계: JSDoc으로 타입 추가
3단계: .js → .ts 파일 변환 (느슨한 설정)
4단계: strict 모드 점진적 활성화
5단계: any 제거 + 완전한 타입 커버리지
1단계: TypeScript 설치와 기본 설정
npm install --save-dev typescript
npx tsc --init
// tsconfig.json — 가장 느슨한 설정으로 시작
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"allowJs": true, // JS 파일 허용
"checkJs": false, // JS 파일 타입 체크 안 함 (처음에는)
"outDir": "./dist",
"rootDir": "./src",
"strict": false, // 처음에는 느슨하게
"esModuleInterop": true,
"skipLibCheck": true,
"noEmit": true // 번들러가 있다면
},
"include": ["src/**/*"]
}
이 설정만으로도 TypeScript 컴파일러가 프로젝트를 인식합니다. 기존 JS 코드는 전혀 수정하지 않아도 됩니다.
2단계: JSDoc으로 타입 추가
파일 확장자를 바꾸지 않고도 JSDoc으로 타입 정보를 추가할 수 있습니다.
// utils.js — JSDoc으로 타입 추가
/**
* @param {string} name
* @param {number} age
* @returns {{ name: string, age: number }}
*/
function createUser(name, age) {
return { name, age };
}
/** @type {string[]} */
const tags = ['javascript', 'typescript'];
/**
* @typedef {Object} Config
* @property {string} host
* @property {number} port
* @property {boolean} [ssl]
*/
/** @type {Config} */
const config = { host: 'localhost', port: 3000 };
// tsconfig.json — checkJs 활성화
{
"compilerOptions": {
"checkJs": true // JS 파일도 타입 체크
}
}
checkJs를 켜면 JSDoc 타입 정보를 기반으로 JS 파일도 타입 체크됩니다.
3단계: .js → .ts 변환
가장 중요한 파일부터 하나씩 .ts로 변환합니다.
변환 우선순위
- 유틸리티 함수 — 의존성이 적고 독립적
- ** 타입/인터페이스 정의** — 다른 파일에서 사용
- ** 핵심 비즈니스 로직** — 타입 안전성이 가장 중요한 곳
- ** 컴포넌트** — 점진적으로
변환 시 주의점
// JS에서 변환할 때 흔한 패턴
// ❌ JS 패턴 — 동적 속성 추가
const user = {};
user.name = '홍길동'; // Error: Property 'name' does not exist
// ✅ TS로 변환
const user: { name: string } = { name: '홍길동' };
// 또는
interface User { name: string; }
const user: User = { name: '홍길동' };
// 일단 any로 변환 후 나중에 개선
function processData(data: any): any {
// TODO: 타입 추가
return data.map((item: any) => item.value);
}
4단계: strict 옵션 점진적 활성화
한꺼번에 strict: true를 켜면 에러가 폭발할 수 있습니다. 하나씩 켜는 것이 좋습니다.
// 활성화 순서 (추천)
{
"compilerOptions": {
"strict": false,
// 1단계: 가장 영향이 적은 것부터
"noImplicitAny": true, // any 추론 금지
// 2단계
"strictNullChecks": true, // null/undefined 분리
// 3단계
"strictFunctionTypes": true, // 함수 매개변수 반공변
// 4단계
"strictPropertyInitialization": true, // 클래스 속성 초기화
// 최종: 모든 것을 strict: true로
// "strict": true
}
}
noImplicitAny 대응
// 에러 발생 위치에 타입을 추가
// ❌ Parameter 'data' implicitly has an 'any' type
function process(data) { /* ... */ }
// ✅ 타입 추가
function process(data: unknown) { /* ... */ }
// 또는 일단 any를 명시 (나중에 개선)
function process(data: any) { /* ... */ }
strictNullChecks 대응
// ❌ Object is possibly 'null'
const element = document.getElementById('app');
element.textContent = 'hello'; // Error
// ✅ null 체크 추가
const element = document.getElementById('app');
if (element) {
element.textContent = 'hello';
}
5단계: any 제거
프로젝트 전체에서 any를 점진적으로 제거합니다.
# any 사용 현황 확인
npx tsc --noEmit | grep 'any'
// ESLint로 any 사용을 경고
{
"rules": {
"@typescript-eslint/no-explicit-any": "warn" // 처음에는 warn, 나중에 error
}
}
유용한 도구
ts-migrate
# Airbnb의 자동 마이그레이션 도구
npx ts-migrate-full <project-dir>
ts-migrate는 JS 파일을 TS로 자동 변환하고, 타입 에러가 나는 곳에 any를 자동으로 추가합니다. 나중에 any를 하나씩 개선하면 됩니다.
마이그레이션 체크리스트
| 단계 | 작업 | 확인 |
|---|---|---|
| 1 | TypeScript 설치, allowJs 설정 | |
| 2 | @types 패키지 설치 | |
| 3 | 핵심 파일 .ts 변환 | |
| 4 | noImplicitAny 활성화 | |
| 5 | strictNullChecks 활성화 | |
| 6 | strict: true 전체 적용 | |
| 7 | any 제거 (95% 이상) | |
| 8 | ESLint typescript-eslint 적용 |
정리
- 마이그레이션은 한 번에 하지 않고 점진적으로 진행한다
allowJs로 JS와 TS를 혼합 운영하면서 하나씩 전환한다- JSDoc으로 파일 확장자 변경 없이도 타입을 추가할 수 있다
- strict 옵션은 하나씩 켜면서 에러를 관리한다
ts-migrate같은 자동화 도구를 활용하면 초기 작업이 빨라진다
댓글 로딩 중...