Item 41 any의 진화를 이해하기

Implicit any(암시적 any)를 이해하자

any 타입은 코드가 진행되면서 '진화(evolve)'한다.

function range(start: number, limit: number) {
  const out = [] // any[]로 선언됨. 
  for (let i = start; i < limit; i++) {
    out.push(i)
  }
  return out // 반환 타입이 number[]로 추론됨.
}

조건문에서는 분기에 따라 타입이 변할 수 있다.

let val   // 타입이 any
if (Math.random() < 0.5) {
  val = /hello/
  val     // 타입이 RegExp
} else {
  val = 12
  val     // 타입이 number
}
val       // 타입이 number | RegExp

변수의 초깃값이 null인 경우에도 any의 진화가 일어난다. 보통 try/catch 블록 안에서 변수를 할당할 경우 나타난다.

let val = null  // 타입이 any
try {
  somethingDangerous()
  val = 12
  val           // 타입이 number
} catch (e) {
  console.warn('alas'!)
}
val             // 타입이 number | null

이런 식으로 any 타입을 명시하지 않았는데도 any 타입으로 선언되는 것을 암시적 any(implicit any)라고 한다.

any 타입의 진화는 noImplicitAny가 설정된 상태에 변수의 타입이 암시적 any인 경우에만 일어난다.

반대로 명시적으로 any를 선언하면 타입이 그대로 유지된다.

let val: any  // 타입이 any
if (Math.random() < 0.5) {
  val = /hello/
  val         // 타입이 any
} else {
  val = 12
  val         // 타입이 any
}
val           // 타입이 any

다음처럼 암시적 any 상태에서 변수에 어떠한 할당도 하지 않고 사용하려고 하면 암시적 any 오류가 발생한다.

function range(start: number, limit: number) {
  const out = []
     // ~~~ 'out' 변수는 형식을 확인할 수 없는 경우 일부 위치에서 암시적으로 'any[]' 형식이다.
  if (start === limit) {
    return out
        // ~~~ 'out' 변수는 암시적으로 'any[]' 형식이 포함된다.
  }
  for (let i = start; i < limit; i++) {
    out.push(i)
  }
  return out
}

any 타입의 진화는 암시적 any 타입어떤 값을 할당할 때만 발생한다.

다음 forEach 안의 화살표 함수는 추론에 영향을 미치지 않는다.

function makeSquares(start: number, limit: number) {
  const out = []
     // ~~~ 'out' 변수는 일부 위치에서 암시적으로 'any[]' 형식이다.
  range(start, limit).forEach((i) => {
    out.push(i * i)
  })
  return out
      // ~~~ 'out' 변수는 암시적으로 'any[]' 형식이 포함된다.
}

Summary

  • 일반적인 타입들은 정제되기만 하는 반면, 암시적 anyany[] 타입은 진화할 수 있다. 이러한 동작이 발생하는 코드를 인지하고 이해할 수 있어야 한다.

  • any를 진화시키는 방식보단 명시적 타입 구문을 사용하는 게 안전한 타입을 유지하는 더 좋은 방법이다.

Last updated