본문 바로가기
Q&A해결2026년 7월 25일1분 읽기

if로 undefined 체크를 했는데도 콜백 안에서는 TS가 또 undefined일 수 있다고 하네요

t
ts_nari
조회 731댓글 1

타입스크립트에서 옵셔널 프로퍼티를 다루는데요, 분명히 위에서 if로 존재 여부를 확인했는데 그 아래 콜백 안으로 들어가면 다시 undefined일 수 있다고 빨간 줄이 그어집니다.

function render(user?: User) {
  if (user) {
    items.forEach(item => {
      console.log(user.name, item)  // Object is possibly 'undefined'.
    })
  }
}

바로 위 if에서 user가 truthy인 걸 확인했잖아요? 그런데 forEach 콜백 안에서는 user가 또 undefined일 수 있다고 하니 이해가 안 됩니다. if 블록 바로 안에서 user.name을 찍으면 에러가 안 나거든요. 콜백에 들어가는 순간만 이래요. 왜 이런 건가요?

댓글 1

김김영삼3개월 전
타입 좁힘(narrowing)이 콜백 경계를 넘으면서 풀린 겁니다. TS 입장에서 forEach에 넘긴 화살표 함수는 "언제 실행될지 모르는" 함수예요. 지금 당장 도는지, 나중에 도는지 컴파일러는 보장 못 하죠. 그 사이에 user가 다른 코드에 의해 다시 undefined로 재할당될 가능성이 있으면 좁힘을 유지해줄 수가 없습니다. 그래서 콜백 안에서는 원래 선언 타입인 User | undefined로 되돌아가는 거예요.

핵심은 user가 재할당 가능한 변수(파라미터나 let)라는 점입니다. 재할당될 수 있으니 TS가 콜백 안에서의 값을 신뢰 못 하는 거죠. 그래서 가장 깔끔한 해결은 좁혀진 값을 const 지역변수로 한 번 복사하는 거예요.

if 안에서 const u = user 이렇게 잡아두고 콜백 안에서는 u.name을 쓰면 됩니다. u는 const라 절대 재할당이 안 되니, TS가 콜백 안에서도 좁힘(User 타입)을 그대로 유지해줍니다. 이 패턴이 제일 무난해요.

다른 방법으로는 콜백 안에서 user?.name처럼 옵셔널 체이닝을 쓰거나, 아예 함수를 (user: User) 형태로 받도록 초반에 가드하고 리턴해버리는(early return) 방식도 있습니다. 참고로 만약 user가 let이 아니라 처음부터 const였다면 이 문제 자체가 안 생겨요. 재할당 불가능한 변수는 콜백 안에서도 좁힘이 유지되거든요. 그래서 지역에선 되도록 const를 쓰는 습관이 이런 잔에러를 줄여줍니다.
Ctrl+Enter로 등록