"any는 검사를 끄고, unknown은 검사를 미루고, never는 가능한 값이 없다고 선언해."
any: 타입 시스템에서 빠져나가는 문
any에는 무엇이든 넣을 수 있고, 그 값에 무엇이든 할 수 있어. 존재하지 않는 속성을 읽고 함수처럼 호출해도 컴파일러가 막지 않아. 한 번 any가 계산에 섞이면 결과도 any로 퍼지기 쉬워서 주변 타입의 보장까지 조용히 약해진다.
낡은 JavaScript 라이브러리나 점진적 이전 과정에서 잠깐 필요할 수는 있어. 그럴 때도 범위를 좁히고 왜 필요한지 보이게 해. any는 ‘어떤 타입이든’이라는 넓은 타입이 아니라 ‘여기서는 타입 검사를 하지 않겠다’는 선택이야.
unknown: 믿기 전의 값
unknown도 무엇이든 받을 수 있지만 곧바로 사용할 수는 없어. 문자열 메서드를 부르려면 typeof x === 'string'으로 확인하고, 객체 속성을 읽으려면 모양을 검증해야 해. 외부 JSON, 사용자 입력, catch 변수처럼 아직 신뢰할 근거가 없는 값에 알맞아.
unknown은 불편함을 만드는 타입이 아니라 검증해야 할 경계를 표시하는 타입이야. 한 번 안전하게 좁히면 안쪽에서는 정확한 타입으로 계속 흐른다. 입력 경계에서 unknown을 쓰고 검증 뒤 도메인 타입으로 바꾸는 구조가 가장 읽기 좋아.
never: 가능한 값이 하나도 없는 자리
never는 어떤 값도 들어올 수 없는 타입이야. 항상 예외를 던지는 함수, 끝없이 도는 함수의 반환 타입에서 나타날 수 있어. 더 실용적인 자리는 유니언의 모든 경우를 처리한 뒤야. 남은 값이 정말 없다면 변수는 never로 좁혀져.
그래서 assertNever(x: never) 같은 함수가 완전성 검사에 쓰여. 새 변형을 유니언에 추가하고 switch 처리를 빼먹으면 x가 더는 never가 아니므로 컴파일 오류가 생겨. 컴파일러가 빠진 경우의 작업 목록을 만들어 주는 셈이지.
셋을 한 줄로 비교해
any는 값의 타입을 알고 싶지 않을 때, unknown은 아직 알지 못해 확인이 필요할 때, never는 값이 존재할 수 없을 때 써. 특히 any와 unknown을 ‘둘 다 아무거나’로 묶지 마. 하나는 안전장치를 끄고 다른 하나는 안전장치가 작동하도록 멈춰 세워.