TypeScript 4.6 strictNullChecks와 조건부 타입 개선

배경

프로젝트 TypeScript를 4.5에서 4.6으로 업그레이드했다. 빌드 시 예상치 못한 타입 에러가 몇 건 발생해서 원인을 파악했다.

주요 변경사항

Control Flow Analysis 개선

4.6에서 destructuring 패턴에 대한 타입 narrowing이 강화됐다.

interface User {
  name: string;
  email?: string;
}

function processUser(user: User) {
  const { email } = user;
  
  if (email) {
    // 4.5: email이 여전히 string | undefined
    // 4.6: email이 string으로 narrowing됨
    console.log(email.toUpperCase());
  }
}

기존에는 조건문 안에서도 email! 처럼 non-null assertion을 써야 했는데, 이제는 불필요해졌다.

인덱스 시그니처에서의 타입 추론

type Dict = { [key: string]: string | number };

const data: Dict = {
  name: "John",
  age: 30
};

// 4.6부터 각 프로퍼티의 구체적 타입 유지
const name = data.name; // string | number (이전과 동일)

완전히 해결된 건 아니지만, 일부 케이스에서 타입 추론이 더 정확해졌다.

발생한 문제

Optional Chaining과 함께 사용 시

interface Response {
  data?: {
    items: string[];
  };
}

function getFirstItem(res: Response) {
  // 4.6에서 더 엄격하게 체크
  return res.data?.items[0]; // 이전엔 통과, 이제 에러
  // 올바른 방식
  return res.data?.items?.[0];
}

옵셔널 체이닝 후 인덱스 접근 시 추가 체크가 필요해졌다.

마이그레이션 팁

  1. strictNullChecks: true 상태에서 업그레이드 권장
  2. 기존 non-null assertion 사용 부분 재검토
  3. 테스트 코드부터 점진적으로 수정

전반적으로 타입 안정성이 높아져서 긍정적이었다. 초기 마이그레이션에 하루 정도 소요됐다.