TypeScript 'Type is unknown' 에러 원인 및 해결 방법: Type Guard 활용하기
1. any와 unknown의 치명적인 차이점
타입스크립트(TypeScript)를 처음 접하는 개발자들이 가장 당황하는 순간은 컴파일러가 Object is of type 'unknown'이라는 붉은 줄을 띄울 때입니다. 과거 자바스크립트의 동적 타이핑에 익숙했던 개발자들은 귀찮음을 피하기 위해 any 타입을 남발하곤 했습니다. 하지만 any는 타입스크립트의 존재 이유 자체를 부정하는 '타입 검사 포기' 선언과 같습니다. any를 지정한 변수는 어떤 메서드를 호출하든 컴파일러가 조용히 넘어가며, 결국 런타임에 치명적인 에러를 발생시킵니다.
반면, 타입스크립트 3.0에서 도입된 unknown은 "이 변수에 무슨 값이 들어올지 아직 모른다"는 보다 안전한 선언입니다. 어떤 값이든 할당받을 수 있다는 점에서는 any와 동일하지만, unknown 타입인 변수의 프로퍼티에 접근하거나 메서드를 호출하려고 하면 컴파일러가 가차 없이 에러를 뱉어냅니다. 즉, "네가 이 변수를 사용하고 싶다면, 먼저 이 변수의 진짜 타입이 무엇인지 증명해내라"라고 강제하는 매우 강력한 방어기제입니다.
이러한 엄격함 덕분에 unknown은 외부 API 응답 데이터, 사용자 입력값, 혹은 예측할 수 없는 라이브러리 반환값을 받을 때 최우선으로 사용해야 하는 방어적 타입으로 자리매김했습니다.
2. try-catch 블록에서의 unknown 에러 처리
unknown 에러가 가장 빈번하게 터지는 곳은 바로 try-catch 구문 안의 catch (error) 블록입니다. 타입스크립트 4.4 버전부터 catch 블록에서 잡히는 error 객체의 기본 타입이 any에서 unknown으로 변경되었습니다. 자바스크립트에서는 꼭 Error 객체뿐만 아니라 문자열, 숫자, 심지어 null까지 throw할 수 있기 때문에 이러한 엄격한 조치는 문법적으로 완벽히 타당합니다.
따라서 아래와 같이 error.message에 바로 접근하려고 하면 에러가 발생합니다.
try {
throw new Error("뭔가 잘못되었습니다");
} catch (error) {
// Error: Object is of type 'unknown'
console.log(error.message);
}3. 타입 가드(Type Guard)를 통한 우아한 해결책
이 문제를 해결하기 위해서는 런타임에 변수의 실제 타입을 확인하여 범위를 좁혀주는 '타입 가드(Type Narrowing)' 기법을 사용해야 합니다. 가장 대표적인 방법은 instanceof 연산자를 사용하는 것입니다.
catch (error) {
if (error instanceof Error) {
// 이 블록 안에서 error는 완벽한 Error 타입으로 인정받습니다.
console.log(error.message);
} else if (typeof error === 'string') {
// 누군가 throw "문자열 에러" 를 했을 때의 처리
console.log("에러:", error);
} else {
console.log("알 수 없는 에러 발생:", String(error));
}
}
또한, API 통신 결과로 받아온 알 수 없는 JSON 데이터(unknown)를 다룰 때는 typeof 연산자를 사용하거나, 커스텀 타입 가드 함수(value is Type 구문)를 직접 작성하여 런타임 데이터의 형태가 내가 정의한 인터페이스와 완벽히 일치하는지 검증하는 과정을 거쳐야만 합니다.
4. 커스텀 타입 가드(Custom Type Guard) 함수 작성법
복잡한 객체를 검증할 때는 in 연산자만으로는 한계가 있습니다. 이때 반환 타입으로 arg is Type을 명시하는 커스텀 타입 가드를 만들면 매우 우아하게 코드를 구성할 수 있습니다.
interface User {
id: number;
name: string;
}// 사용자 정의 타입 가드
function isUser(obj: unknown): obj is User {
return typeof obj === 'object' && obj !== null && 'id' in obj && 'name' in obj;
}
const data: unknown = fetchUserData();
if (isUser(data)) {
// 여기서부터 data는 완벽한 User 타입으로 추론됩니다.
console.log(data.name);
}
5. 자주 묻는 질문 (FAQ)
Q. 타입 단언(Type Assertion, as 키워드)을 사용해서 억지로 타입을 맞추면 안 되나요?
error as Error 형태로 컴파일러를 속이는 것은 가장 피해야 할 안티 패턴입니다. 만약 누군가 throw "String Error"를 발생시켰다면 런타임에 error.message는 undefined를 반환하며 앱이 오동작하게 됩니다. 타입 단언은 개발자가 100% 확신하는 극히 제한적인 상황(예: DOM 요소 선택)에서만 써야 합니다.
Q. Zod나 Yup 같은 스키마 검증 라이브러리가 왜 유행하나요?
서버에서 날아온 JSON 데이터는 타입스크립트 입장에서는 완벽한 unknown입니다. 일일이 if (typeof data.id === 'number') 같은 보일러플레이트 코드를 작성하는 것은 엄청난 고통이기 때문에, Zod와 같은 라이브러리를 통해 런타임 스키마 검증과 타입 추론을 동시에 자동화하는 것이 현대 프론트엔드의 트렌드입니다.
Q. unknown 타입에 절대 불가능한 값을 넣으면 어떻게 되나요?
unknown 타입에는 말 그대로 '모든 값'이 할당 가능합니다. 그러나 할당하는 것은 자유롭지만, 빼내어 사용할 때는 반드시 검문소(타입 가드)를 통과해야만 허락해 주는 것이 unknown의 핵심 철학입니다.
OMANGAZI 편집팀
최신 IT 기술, 오픈소스 AI 생태계, 그리고 모던 웹 개발 트렌드를 연구하고 분석합니다. 단순한 정보 전달을 넘어 개발자들의 실무에 도움이 되는 깊이 있는 인사이트를 제공합니다.