any, unknown, never — 탈출구와 불가능의 타입
any는 타입 검사를 끄는 것이고,unknown은 타입 검사를 ** 미루는** 것이며,never는 ** 존재할 수 없는** 값의 타입입니다.
이 세 가지는 면접에서 거의 반드시 물어보는 주제입니다.
any — 타입 검사의 탈출구
any는 어떤 타입이든 할당 가능하고, 어떤 연산이든 허용합니다.
let value: any = 42;
value = 'hello'; // OK
value = true; // OK
value.foo.bar.baz; // OK — 런타임에 에러가 나더라도 컴파일은 통과
value(); // OK
value[0]; // OK
any는 전염된다
const data: any = fetchSomething();
const name = data.user.name; // name: any — any가 전파됨
const upper = name.toUpperCase(); // upper: any
// any가 한 번 들어가면 그 이후 모든 타입 검사가 무의미해짐
any를 써야 할 때
// 1. JavaScript에서 마이그레이션 중일 때 (임시방편)
// 2. 서드파티 라이브러리에 타입 정의가 없을 때
// 3. 정말로 어떤 타입이든 받아야 하는 유틸리티 함수
// → 이 경우에도 unknown이 더 좋은 선택
unknown — 안전한 any
unknown은 any처럼 어떤 타입이든 할당 가능하지만, ** 사용하기 전에 타입을 좁혀야** 합니다.
let value: unknown = 42;
value = 'hello'; // OK — 할당은 자유
value = true; // OK
// ❌ 하지만 바로 사용은 불가
// value.toUpperCase(); // Error: Object is of type 'unknown'
// value(); // Error
// value[0]; // Error
// ✅ 타입을 좁힌 후 사용
if (typeof value === 'string') {
console.log(value.toUpperCase()); // OK
}
unknown의 실전 활용
// API 응답 처리 — 무엇이 올지 모르는 외부 데이터
async function fetchData(url: string): Promise<unknown> {
const response = await fetch(url);
return response.json();
}
// 사용할 때 타입을 검증
const data = await fetchData('/api/user');
// 타입 가드로 검증
function isUser(data: unknown): data is { name: string; age: number } {
return (
typeof data === 'object' &&
data !== null &&
'name' in data &&
'age' in data
);
}
if (isUser(data)) {
console.log(data.name); // OK — data는 { name: string; age: number }
}
면접 포인트: "any 대신 unknown을 쓰는 이유가 뭔가요?"라고 물어보면, "unknown은 사용 전에 타입 좁히기를 강제하므로 타입 안전성을 유지할 수 있습니다"라고 답하면 됩니다.
never — 존재할 수 없는 값
never는 ** 어떤 값도 가질 수 없는 타입 **입니다. "이 코드는 절대 도달하지 않는다"를 의미합니다.
never가 되는 경우
// 1. 항상 예외를 던지는 함수
function throwError(message: string): never {
throw new Error(message);
}
// 2. 무한 루프
function forever(): never {
while (true) {}
}
// 3. 모든 경우를 처리한 후의 남은 타입
type Shape = 'circle' | 'square';
function getArea(shape: Shape): number {
switch (shape) {
case 'circle':
return Math.PI;
case 'square':
return 1;
default:
// shape: never — 모든 경우를 이미 처리했으므로
const _exhaustive: never = shape;
return _exhaustive;
}
}
exhaustiveness check (완전성 검사)
never의 가장 실용적인 활용입니다.
type Animal = 'dog' | 'cat' | 'bird';
function makeSound(animal: Animal): string {
switch (animal) {
case 'dog': return '멍멍';
case 'cat': return '야옹';
case 'bird': return '짹짹';
default:
// 새로운 동물이 추가되면 여기서 컴파일 에러 발생
const _never: never = animal;
throw new Error(`처리되지 않은 동물: ${_never}`);
}
}
// 나중에 Animal에 'fish'를 추가하면
// type Animal = 'dog' | 'cat' | 'bird' | 'fish';
// → default에서 에러: Type 'fish' is not assignable to type 'never'
세 타입의 관계
타입 계층에서의 위치
// unknown은 모든 타입의 슈퍼타입 (Top Type)
// any는 타입 시스템을 벗어남 (특수한 존재)
// never는 모든 타입의 서브타입 (Bottom Type)
// unknown: 모든 타입이 할당 가능
const a: unknown = 42;
const b: unknown = 'hello';
const c: unknown = true;
// never: 어떤 타입에도 할당 가능 (값이 없으므로 논리적으로 참)
function getDefault(): never {
throw new Error('no default');
}
const num: number = getDefault(); // OK (never는 number에 할당 가능)
const str: string = getDefault(); // OK (never는 string에 할당 가능)
// 하지만 never에 할당하는 것은 불가
// const n: never = 42; // ❌ Error
연산에서의 동작
// 유니온에서 never는 사라짐
type A = string | never; // string
type B = number | never; // number
// 인터섹션에서 never는 전체를 never로 만듦
type C = string & never; // never
// 유니온에서 unknown은 전체를 unknown으로 만듦
type D = string | unknown; // unknown
// 인터섹션에서 unknown은 사라짐
type E = string & unknown; // string
any vs unknown vs never 비교
| 특성 | any | unknown | never |
|---|---|---|---|
| 할당 가능한 값 | 모든 값 | 모든 값 | 없음 |
| 다른 타입에 할당 | 가능 | 좁히기 필요 | 가능 |
| 연산/접근 | 자유 | 좁히기 필요 | 불가 |
| 타입 안전성 | 없음 | 있음 | 완전함 |
| 용도 | 임시 탈출구 | 외부 데이터 | 불가능한 상태 |
실전 팁
// ❌ any 사용
function parse(json: string): any {
return JSON.parse(json);
}
const data = parse('{"name": "test"}');
data.whatever.something; // 타입 에러 없이 런타임 에러
// ✅ unknown 사용
function parseSafe(json: string): unknown {
return JSON.parse(json);
}
const safeDaata = parseSafe('{"name": "test"}');
// safeData.whatever; // ❌ 컴파일 에러 — 타입 좁히기를 강제
정리
any는 타입 검사를 끄는 것이므로 가능한 피한다unknown은 안전한any로, 외부 데이터 처리에 적합하다never는 불가능한 상태를 나타내며, exhaustiveness check에 활용한다- 타입 계층:
never(바닥) → 각 타입 →unknown(꼭대기) - 유니온에서
never는 사라지고,unknown은 전체를 삼킨다
댓글 로딩 중...