dogAndCat은 Dog 타입의 원소와 Cat 타입의 원소를 갖는 배열이다. 이러한 배열의 타입은 어떻게 추론해야 할까?
이런 상황에서 타입스크립트는 최적 공통 타입(best common type)이란 접근법을 사용한다. 원리는 간단한데, 모든 가능한 타입의 유니온 타입을 사용하는 것이다. 예를 들어 위 dogAndCat의 타입을 Array<Dog | Cat> 으로 추론하는 식이다.
이 때 두 인터페이스 모두 Animal 인터페이스를 호환받았으니 Array<Animal>로 추론하면 되는 것 아닐지 궁금해 할 수 있다. 그렇게 동작하지 않는 이유를 이해하기 위해 다음 예제를 보자.
타입스크립트는 최적 공통 타입에 따라 dogAndCat를 Array<Dog | Cat> 타입으로 추론한다. 따라서 다음 코드는 실제로 타입 검사를 통과한다. 아래 코드는 실제로 문제가 생길 여지가 없으므로 이는 바람직한 동작이다.
하지만 만약 배열의 타입을 Array<Animal>로 추론한다면 어떻게 될지 생각해보자. getSoundFunction 함수는 Camel 타입을 인자로 받지 않는다. 그 때문에, dogAndCat 내에는 Camel 타입 값이 존재하지 않음에도 위의 코드에선 타입 에러가 날 것이다.
이런 불편함을 막고자, 최적 공통 타입에서는 타입 추론에 사용된 값들의 타입(이 경우엔 Dog와 Cat)만을 재료로 사용한다. dogAndCat이 Array<Animal> 타입을 갖길 원한다면 타입 추론에 의존하는 대신 명시적으로 타입 표기를 해 주면 된다.
문맥 상의 타입
할당이 일어날 때, 타입 추론은 할당 받는 값(왼쪽 항)의 타입 뿐만 아니라 할당하는 값(오른쪽 항)의 타입에 대해서도 일어난다. 이렇게 추론된 타입을 문맥 상의 타입(contextual type)이라 부른다.
이 때, Window 인터페이스의 onmousedown 속성은 아래와 같이 정의되어 있다.
따라서 타입스크립트는 우변의 함수가 (event: MouseEvent) => void 타입일 것이라고 추론한다. 이 때 함수 내부에서 event.a 속성에 접근하는데, a 속성은 MouseEvent 타입에 존재하지 않으므로 타입 에러가 발생한다.
만약 타입 표기가 주어졌다면 문맥 상의 타입은 무시된다. 예를 들어, 다음과 같이 mouseEvent 매개변수의 타입을 표기해주면 위의 에러는 사라진다.