타입 추론이 가능한 특정 범위 안에서 타입을 보장해서 타입 단언이 해결하지 못하는 런타임 에러를 방지할 수 있음
가드에 자주 쓰이는 방법들
(어떤 객체인지 판단할 때) 속성 in 객체
if ('privileges' in emp) {
console.log(emp.privileges) // 가드가 없으면 에러가 난다
}
instanceof
객체를 타입처럼,, (JS에도 있는 것,)
타입 단언으로 null이 아닐거라고 단언해놓고 실제론 null이 들어와 버리면 안되니, 타입단언 대신 타입가드로 방어
런타임 시 실행된다
instanceof 뒤에 나오는건 모두 객체 타입(HTMLButtonElement, String, Object, Date, 커스텀객체)
인터페이스는 js로 컴파일되지 않기 때문에 ‘instaceof 인터페이스’는 쓸 수 없다.
const btn = document.querySelector('button')
if (btn instanceof HTMLButtonElement) { //if(btn)보다 더 세밀한 가드방법
btn.classList.add('btn')
btn.id = 'abc'
}
typeof
(주의) typeof해서 나오는 타입에선 커스텀 타입은 나올 수 없다 ⇒ intanceof 사용 ㅇㅇ
typeof의 값들은 모두 소문자로 된 문자열 (ex. ‘object’, ‘string’, ‘number’..)
function toTwoDecimals(val: number | string) {
if (typeof val === 'number') { //타입 가드
val.toFixed(2)
} else {
val.slice(0,2)
}
}
변수 is 타입
타입 체크하는 로직을 함수로 만들 때 사용
반환 값을 변수 is 타입으로 해서, 타입의 일치 여부를 확인하는 함수라고 명시
function isNum(val: unknown): val is number { // 반환값으로 함수가 뭘 체크하는지 알려줌
return typeof val === 'number' // 타입이 숫자인지 여부
}
function toTwoDecimals(val: number | string) {
if (isNum(val)) { // 타입 체크 함수로 가드
val.toFixed(2)
} else {
val.slice(0,2)
}
}
type UserA = { name: string; age: number}
function isUserA(user: unknown): user is isUserA{
const userA = user as UserA // 타입 단언
return user && typeof user === 'object'
&& typeof userA.name === 'string' && typeof userA.age === 'number'
// 타입 단언으로 컴파일 에러를 일단 막고, 타입가드를 통해 실제로 타입이 맞는지 확인하여 런타임 에러 방지
}
인터페이스의 타입 가드
두개 이상의 인터페이스를 유니온한 타입일 때, 실제로 어떤 인터페이스 타입이 들어왔는지 확인하고 싶지만 인터페이스는 instaceof으로 구별이 불가하다
따라서 인터페이스들에 공통된 속성과 값을 리터럴로 줘서 이 값들에 따라 어떤 인터페이스인지 판단하는 방법을 사용할 수 있다
검사할 때, 컴파일러가 공통된 속성의 값으로 뭐가 올 수 있는지 이미 알고 있다
interface Bird {
type: "bird" //타입이 아니라 리터러ㅓㄹ
..
}
interface Horse {
type: "horse"
..
}
function isAnimal (animal: Bird | Horse) {
switch(animal.type) {
case "bird":
...
case "horse":
...
}
}