any에는 타입 안정성이 없다

따라서 코드의 혼란이 가중된다.

let age: number
age = '12'
// Type 'string' is not assignable to type 'number'.

age = '12' as any // OK

any는 함수 시그니처를 무시해 버린다

함수 시그니처란 함수 작성 시 명시되어 있는 입력과 출력의 타입을 의미한다. any 타입을 사용하면 이런 약속을 어길 수 있다.

function calculateAge(birthDate: Date): number {
  // ...
}

let birthDate: any = '1990-01-19'
calculateAge(birthDate) // OK

위의 코드에서도 Date 타입인 birthDate에 string이 들어갔다면 어떤 문제가 발생할지 예측할 수 없다.

any 타입에는 언어 서비스가 적용되지 않는다

any 타입을 사용하면 자동완성 기능의 도움을 받을 수 없다.

let person: any = { first: 'George', last: 'Washington' }
person.  // 자동완성으로 first와 last가 나오는 게 인지상정

Rename Symbol을 통해 속성 값을 통째로 변경할수도 없다.

interface Person { 
  first: string 
  last: string
}

const formatName = (p: Person) => `${p.first} ${p.last}`
const formatNameAny = (p: any) => `${p.first} ${p.last}`

// => formatName의 first 심볼을 Rename Symbol을 통해 firstName으로 변경

interface Person { 
  firstName: string 
  last: string
}

const formatName = (p: Person) => `${p.firstName} ${p.last}`
const formatNameAny = (p: any) => `${p.first} ${p.last}` // 변경되지 않음

any 타입은 코드 리팩터링 때 버그를 감춘다

interface ComponentProps {
  onSelectItem: (item: any) => void
}

function renderSelector(props: ComponentProps) { /** ... */ }

let selectedId: number = 0

function handleSelectItem(item: any) {
  selectedId = item.id
}

renderSelector({ onSelectItem: handleSelectItem })

위에서 onSelectItem에 아이템 객체를 통째로 넘겨주지 않고 필요한 부분만 전달하도록 리팩토링 해보자.

interface ComponentProps {
  onSelectItem: (id: number) => void
}