[any 41] any 타입의 진화(evolve)

2022. 7. 28. 14:55책/이펙티브 타입스크립트

1. any 진화

진화란 말이 뭔가 거창해보일 수 있는데, 변수의 타입이 암시적 any 타입에 어떤 값을 할당하면 해당 값으로부터 타입을 추론해 타입이 변하는 일을 말한다. 

any any[ ]타입이나 초기값딩 null인 경우도 any의 진화가 발생한다. Type narrowing과는 다른 개념으로, noImplicitAny이 설정된 상태에서만 일어난다. 

1) 변수 any타입의 진화
let val; // any
val = /hello/; //RegExp
val = 12; // number

2) if나 try..catch문에서도 쉽게 보인다
if (Math.random() < 0.5) {
    val = /hello/
} else {
    val = 12
}
// val : number | RegExp

3) 변수 any[] 타입의 진화
const result = [];
result.push('a') // string[]
result.push(11) // (string | number) []

function range(start :number, limit :number) {
  // 분명 여기선 any[]로 추론돼있는데
  const out = []; // any[]
  for (let i = start; i < limit; i++) {
    out.push(i);
  }

  // 마지막까지 가니까 그냥 number[]로
  // 알아서 잘 추론해주네???
  return out; // number[]
}

 

2. evolve 특징

중요한 특징은 위에서도 언급했지만 암시적 any 타입에 어떤 값을 할당할 때만 일어난다는 점이다. 즉, 암시적 any 타입에 함수 호출을 거친다 하더라도 진화가 일어나지는 않는다. 예를 들어, Array.prototype.forEach 같은 함수를 사용한다한들 타입이 변하지는 않는다.

function range(start :number, limit :number) {
  const out = []; // any[]
  for (let i = start; i < limit; i++) {
    out.push(i);
  }
  return out;
}

function makeSquares(start :number, limit :number) {
    const out = [];

    // ~~~ 'out'변수가 일부 위치에서 암시적 any[]타입인데요??
    range(start, limit).forEach(val => out.push(val))

    // 'out'변수에 암시적 any[] 타입이 포함돼있는데요??
    return out; // any[]
}

 

타입을 알아서 추론해주니 좋아보일 수도 있을지 모르겠다. 그러나 타입 안전성을 지키기 위해서는 암시적 any를 진화시키는 방식보다 명시적 타입 구문을 사용하는게 더 좋은 설계이다.