any는 그 값에 대한 타입 검사를 포기하는 타입이고, unknown은 타입을 아직 모르니 확인하기 전에는 쓰지 못하게 하는 타입이다. 둘 다 아무 값이나 받을 수 있지만, 꺼내 쓸 때가 다르다.
let a: any = 'hi'
a.foo.bar() // 통과 → 런타임에 터짐
const n: number = a // 통과
let u: unknown = 'hi'
u.toUpperCase() // ❌ 먼저 좁혀야 함
if (typeof u === 'string') u.toUpperCase() // ✅unknown은 TS 3.0에서 들어왔다.JSON.parse·fetch().json()·postMessage·localStorage처럼 외부에서 들어오는 값은unknown으로 받고 타입 가드나 Zod 같은 런타임 스키마(Runtime Schema)로 좁힌다catch (e)의e는 무엇이든 throw될 수 있으니unknown이 맞다.useUnknownInCatchVariables(strict에 포함)가 이를 강제한다.e instanceof Error로 확인하고 쓴다- 제네릭의 기본값도
T = any보다T = unknown이 안전하다 any는 퍼진다.any에서 꺼낸 값도any라 오류가 숨겨진 채 코드 전체로 번진다. 정말 타입을 알 수 없는 서드파티 경계에서만 좁게 쓴다never는 반대편 끝이다. 어떤 값도 될 수 없는 타입으로, 끝까지 좁혀진 분기나 절대 반환하지 않는 함수에 나온다(판별 유니언)
검증되지 않은 값을 검증된 값과 타입으로 구분하는 방법은 타입 브랜딩, 신뢰 경계에서의 입력 검증은 Bean Validation·프로토타입 오염과 같은 문제다.