TypeScript
TypeScript에서 unknown 타입을 제대로 다루기
unknown 타입 처리로 발생하는 타입 에러들을 이해하고 안전하게 좁혀가는 방법.
TypeScript를 쓰다 보면 any 대신 unknown 타입을 쓰도록 강요받는 순간이 온다. unknown은 any보다 훨씬 까다롭지만, 제대로 다루면 타입 안정성이 훨씬 높아진다.
unknown은 any와 다르다
any는 거의 모든 작업을 허용하지만, unknown은 타입 가드를 거쳐야만 쓸 수 있다.
function process(value: unknown) {
// value.method() // ❌ 컴파일 에러
if (typeof value === 'string') {
console.log(value.toUpperCase()); // ✅ OK
}
}
이 차이가 실제로 버그를 방지한다.
타입 가드의 여러 방법
typeof 가드
if (typeof value === 'string') { }
if (typeof value === 'number') { }
원시형에는 이것으로 충분하다.
instanceof 가드
if (value instanceof Date) {
value.toISOString(); // Date 메서드 가능
}
클래스 인스턴스 확인에 쓴다.
커스텀 타입 가드
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value
);
}
if (isUser(value)) {
console.log(value.name); // User 타입으로 인정됨
}
복잡한 객체 구조를 다룰 때 필수다.
자주 놓치는 실수들
null 체크 빼먹기
if (typeof value === 'object') {
// ❌ value가 null일 수도 있음
value.property; // 런타임 에러 가능
}
if (typeof value === 'object' && value !== null) {
// ✅ 안전함
value.property;
}
optional 처리 불완전
if ('property' in value) {
// value.property는 unknown
// 여기서 또 타입 가드를 거쳐야 함
}
API 응답 처리할 때
function handleResponse(data: unknown) {
// API 응답을 곧바로 쓰지 말고
const schema = z.object({
id: z.string(),
name: z.string()
});
const parsed = schema.parse(data); // Zod나 Yup 같은 라이브러리 쓰기
return parsed;
}
API 응답은 항상 unknown으로 시작하고, 스키마 검증을 거쳐야 한다.
빌드 시 확인
npm run build
noImplicitAny와 strictNullChecks를 켜둬야 unknown 관련 에러를 모두 잡을 수 있다.
정리
unknown은 결국 "이 값이 뭔지 아직 모르니까 체크하고 쓰자"는 뜻이다. 타입 가드를 한 단계 거치는 것이 처음엔 번거로워 보이지만, 결국 런타임 버그를 많이 줄여준다. 특히 API 응답이나 JSON 파싱 같은 외부 데이터를 다룰 때는 필수다.