TypeScript를 사용하다 보면 “이 값이 어떤 타입인지 개발자가 더 잘 알고 있을 때” 또는 “여러 타입 중 하나의 타입을 안전하게 좁혀야 할 때”가 자주 발생합니다. 이럴 때 사용하는 두 가지 핵심 기능이 타입 단언(Type Assertion)과 타입 가드(Type Guard)입니다.
두 개념은 비슷해 보이지만 목적과 사용 방식이 분명하게 다릅니다.
타입 단언(Type Assertion)이란?
타입 단언은 TypeScript에게 “내가 이 값의 타입을 더 잘 알고 있으니, 이 타입으로 처리해라” 하고 컴파일러에게 알려주는 문법입니다.
const value: any = "hello";
const length = (value as string).length;
타입 단언은 실제 값의 타입을 변경하는 것이 아니라, TypeScript의 타입 체크를 우회하는 것입니다. 따라서 잘못 사용하면 런타임 오류가 발생할 수 있습니다.
타입 단언 사용 방식
1. as 문법
let input = document.getElementById("title") as HTMLInputElement;
2. 앵글 브래킷 문법 (<T>)
let input = <HTMLInputElement>document.getElementById("title");
TSX(React) 환경에서는 HTML 태그와 혼동되기 때문에 as 사용이 권장됩니다.
타입 단언을 사용해야 하는 상황
- DOM 요소 조회 후 타입 보장
- 외부 라이브러리(타입 정의 부족) 사용
- any · unknown 값을 구체적 타입으로 변환
- JSON.parse 결과 처리
const data = JSON.parse('{"name":"Alice"}') as { name: string };
하지만 타입 단언은 어디까지나 “믿고 쓰는 문법”이기 때문에 실제 값과 단언한 타입이 다를 경우 컴파일러가 잡아주지 않는다는 위험성이 있습니다.
타입 가드(Type Guard)란?
타입 가드는 런타임에서 조건을 통해 타입을 좁히고 (narrowing), TypeScript가 코드 흐름을 따라 실제 타입을 안전하게 추론할 수 있게 해주는 기능입니다.
function print(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // string
} else {
console.log(value.toFixed(2)); // number
}
}
타입 가드는 타입 단언과 다르게 컴파일러와 런타임 모두에 안전합니다.
주요 타입 가드 종류
1. typeof 타입 가드
문자열, 숫자, boolean 등 기본 타입 narrowing에 사용됩니다.
if (typeof value === "string") { ... }
2. instanceof 타입 가드
클래스 기반 객체를 좁힐 때 사용합니다.
if (error instanceof Error) { ... }
3. in 연산자 타입 가드
객체 속성 존재 여부로 타입을 좁혀줍니다.
type User = { name: string };
type Admin = { role: string };
function check(u: User | Admin) {
if ("role" in u) {
console.log(u.role); // Admin
}
}
4. 커스텀 타입 가드 (is 키워드)
실무에서 가장 강력한 타입 가드입니다.
type Cat = { meow: () => void };
type Dog = { bark: () => void };
function isCat(animal: Cat | Dog): animal is Cat {
return "meow" in animal;
}
function sound(animal: Cat | Dog) {
if (isCat(animal)) {
animal.meow(); // Cat
} else {
animal.bark(); // Dog
}
}
이 방식은 “복잡한 유니온 타입을 안정적으로 좁혀야 하는 경우”에 필수적으로 사용됩니다.
타입 단언 vs 타입 가드 — 결정적 차이
| 구분 | 타입 단언 | 타입 가드 |
|---|---|---|
| 타입 체크 우회 | O | X |
| 런타임 안전성 | X 낮음 | O 높음 |
| 주 목적 | 컴파일러에게 “이 타입으로 처리해라” | 값의 실제 타입을 판별해 좁히기 |
| 실무 중요도 | 중간 | 매우 높음 |
실무에서의 권장사항
✔ 타입 단언은 최소한으로 사용
타입 단언은 “마지막 수단”이어야 합니다. 특히 any 기반 코드에서 단언을 남용하면 타입 안정성이 무너집니다.
✔ 타입 가드로 실제 값 검증 기반 narrowing 수행
API 응답, dynamic 데이터, 이벤트 핸들링 등 런타임 타입이 다양할 때 타입 가드는 필수 도구입니다.
✔ 커스텀 타입 가드는 복잡한 코드에서 강력
도메인이 커질수록 복잡한 union 타입을 다루게 되는데 이럴 때 커스텀 타입 가드가 유지보수성을 크게 높여줍니다.
타입 단언은 빠르게 타입 체커를 통과시키는 도구이지만, 위험성을 내포하고 있으며 반대로 타입 가드는 실제 타입에 기반한 안전한 방식으로 타입을 좁힐 수 있습니다. TypeScript의 타입 안정성과 유지보수성을 높이기 위해서는 타입 단언보다 타입 가드를 적극적으로 활용하는 것이 좋습니다.
- 타입 단언 = 타입 체크 우회, 위험할 수 있음
- 타입 가드 = 값 기반 안전한 타입 narrowing
- 커스텀 타입 가드 = 복잡한 유니온 처리의 필수 도구
