TypeScript 5.5의 Inferred Type Predicates 도입 후기

문제 상황

프로젝트에서 배열 필터링 시 타입 가드를 자주 사용하는데, 매번 반환 타입을 is 키워드로 명시하는 게 번거로웠다.

// 기존 방식
function isNotNull<T>(value: T | null): value is T {
  return value !== null;
}

const values = [1, null, 2, null, 3];
const filtered = values.filter(isNotNull); // number[]

반환 타입을 명시하지 않으면 타입이 좁혀지지 않아 (number | null)[]로 남았다.

TypeScript 5.5 적용

5.5로 업데이트 후 명시적 type predicate 없이도 타입 추론이 작동했다.

// 5.5 이후
function isNotNull<T>(value: T | null) {
  return value !== null;
}

const filtered = values.filter(isNotNull); // number[]

컴파일러가 함수 본문을 분석해 자동으로 type predicate를 추론한다.

적용 범위

단순 null/undefined 체크뿐 아니라 프로퍼티 존재 여부 확인에도 적용됐다.

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

function hasEmail(user: User) {
  return user.email !== undefined;
}

const users: User[] = [...];
const withEmail = users.filter(hasEmail);
// { id: string; email: string }[]

주의사항

복잡한 로직에서는 여전히 명시적 type predicate가 필요했다. 추론이 실패하는 경우 기존 방식으로 작성하면 된다.

레거시 코드의 기존 type predicate는 호환되므로 점진적 마이그레이션이 가능하다.