Search
🧾

아이템 60~62. 발표 자료

8장. 타입스크립트로 마이그레이션 하기

60. allowJs로 TS와 JS 같이 사용 (사전 작업)

SUMMARY - allowJs 옵션 → .ts & .js 확장자 동시 사용 가능 - test & build 체인에 TS 우선 적용 필요
대규모 프로젝트의 경우 점진적 마이그레이션이 필요 → JS, TS 파일이 공존해야 함
allowJS 옵션: JS파일과 TS파일을 서로 임포트 할 수 있게 함
test & build 체인에 TS 우선 적용 필요

61. 의존성 관계에 따라 모듈 단위로 전환 (순서, 수치화)

SUMMARY - 의존성이 낮은 모듈부터 작업 시작 (서드파티, API 호출, 의존성 최하단 모듈) - 리팩터링추후에 / TS 전환에 따른 오류 조심
점진적 마이그레이션 시에는 모듈 단위 변경이 이상적
일부 모듈 변경 시 의존(해당 모듈 내에서 임포트 해오는) 관련 오류 발생
다른 모듈에 의존하지 않는 (의존성이 낮은) 부분부터 작업 시작 필요
서드파티 라이브러리 (프로젝트 내 모듈에 의존 X) → @types 설치
외부 API (프로젝트 내 모듈에 의존 X) → API 사양 기반 타입 정보 추가
의존성 최하단 모듈 의존성 관계를 시각화
의존성 시각화 툴 활용 (madge 등)
의존성 최하단에는 주로 유틸리티 모듈이 존재
오류 & 주의사항 (4가지)
오류- 선언되지 않은 클래스 멤버
  수정 전
class Greeting { constructor(name) { this.greeting = 'Hello' // ~~~~~~~~ Property 'greeting' does not exist on type 'Greeting' this.name = name // ~~~~ Property 'name' does not exist on type 'Greeting' } // ... }
TypeScript
복사
  수정 후
// 클래스 멤버 변수를 명시적으로 선언 class Greeting { greeting: string; name: any; constructor(name) { this.greeting = 'Hello' this.name = name } // ... }
TypeScript
복사
오류- 타입이 바뀌는 값
  수정 전
const state = {} state.name = 'New York' // ~~~~ Property 'name' does not exist on type '{}' state.capital = 'Albany' // ~~~~~~~ Property 'capital' does not exist on type '{}'
TypeScript
복사
  수정 후
interface State { name: string capital: string } const state = {} as State state.name = 'New York' // OK state.capital = 'Albany' // OK
TypeScript
복사
주의할 점- JS에서 추가 된 타입 정보는 무효화 됨
JS 내에 JSDoc, @ts-check 로 추가된 타입 정보는 무효화 됨 → 빠른 수정을 통한 TS 전환
주의할 점 - 마이그레이션 중에는 다른 리팩터링 X
 마이그레이션 작업 중에는 그 자체에만 집중하고 다른 리팩터링을 해서는 안됨
 추후 리팩터링을 위한 목록 작성 후 작업
마지막 단계 - 테스트 코드 TS 전환
테스트 코드는 항상 의존성 코드에 최상단에 존재
변환 가능한 최하단의 모듈부터 테스트를 수행하며 변환

62. 마이그레이션의 완성을 위해 noImplicityAny 설정 (완성도)

SUMMARY - 마이그레이션 후 noImplicityAny 적용 → 숨은 타입 오류 발견 가능 - noImplicityAny 로컬에 우선 적용 → 점진적 마이그레이션 가능

noImplicityAny의 활용 ❶ - 타입 오류 발견

// tsConfig: {"noImplicitAny":false,"strictNullChecks":false} class Chart { indices: any // index의 복수형 // ... } class Chart { // 빠른 수정에서 any로 추론 된 indices를 임의로 수정 // 사실 indeices는 이차원 배열 (number[][]) indices: number[] getRanges() { // r은 number[] 형태 for (const r of this.indices) { const low = r[0] // Type is any const high = r[1] // Type is any // ... } } } // 만약 noImplicityAny가 설정 시 정확한 타입체크가 되어 '제대로 된 오류 메세지'보여줌 // ~~~~ Element implicitly has an 'any' type because // type 'Number' has no index signature
TypeScript
복사

noImplicityAny의 활용 ❷ - 점진적 마이그레이션

처음에는 noImplicityAny로컬먼저 설정 후 작업하는 것이 좋음
원격 설정에는 변화가 없어 빌드가 실패 X
로컬에만 발생한 오류를 수정커밋 가능 (점진적 마이그레이션)
로컬 오류의 개수진척도로 활용 가능
타입 체커의 강도는 사람들의 숙련도에 따라 차차 올려야 함
noImplicityAny상당히 엄격한 설정 (대부분의 타입 체크를 적용한 수준) → “strict”: true 가 가장 강력
/* 엄격한 유형 검사 옵션 * -------------------------------------------------------------------------------------------- */ "strict": true, /* 모든 엄격한 유형 검사 옵션 활성화 */ // "noImplicitAny": true, /* 명시적이지 않은 'any' 유형으로 표현식 및 선언 사용 시 오류 발생 */ // "strictNullChecks": true, /* 엄격한 'null' 검사 사용 */ // "strictFunctionTypes": true, /* 엄격한 함수 유형 검사 사용 */ // "strictBindCallApply": true, /* 엄격한 'bind', 'call', 'apply' 함수 메서드 사용 */ // "strictPropertyInitialization": true, /* 클래스에서 속성 초기화 엄격 검사 사용 */ // "noImplicitThis": true, /* 명시적이지 않은 'any'유형으로 'this' 표현식 사용 시 오류 발생 */ // "alwaysStrict": true, /* 엄격모드에서 구문 분석 후, 각 소스 파일에 "use strict" 코드를 출력 */ /* 추가 검사 옵션 * -------------------------------------------------------------------------------------------- */ // "noUnusedLocals": true, /* 사용되지 않은 로컬이 있을 경우, 오류로 보고 */ // "noUnusedParameters": true, /* 사용되지 않은 매개변수가 있을 경우, 오류로 보고 */ // "noImplicitReturns": true, /* 함수가 값을 반환하지 않을 경우, 오류로 보고 */ // "noFallthroughCasesInSwitch": true, /* switch 문 오류 유형에 대한 오류 보고 */ // "noUncheckedIndexedAccess": true, /* 인덱스 시그니처 결과에 'undefined' 포함 */
TypeScript
복사
Reference