TypeScript 타입단언, 타입가드
Typescript를 사용하다 보면 타입에 대해서 애매해지는 경우가 발생한다.
이 때 사용 할 수 타입 단언, 타입 가드에 대해 간단히 정리해 보자.
타입단언 (Type assertion)
아래와 같은 예제에서 개발자는 foo
에 대해 타입을 알 수 있지만 Typescript language server에서는 any로 추론을 하게 된다.
let foo; // let foo:any
foo = 10;
foo = "abc";
let bar = foo; // let bar:any
bar = foo as string; // let bar:string
가장 많이 사용되는 경우는 DOM API를 사용할 때이며, 다음과 같다.
아래 예제에서 as HTMLDivElement
로 단언하지 않을 경우 서버는 div
가 null 일 수 있는 상황을 상정하여 오류로 표기하지만 개발자 입장에서는 절대 null 일 수 없는 상황이기에 단언을 하게 될 경우 편하게 코드를 작성해 나갈 수 있다.
let div = document.querySelector("div") as HTMLDivElement; // let div: HTMLDivElement | null
div.innerText;
타입 가드
약간 이름만 들었을 때는 Vue.js의 네비게이션 가드 같은 느낌을 받았지만 비슷하면서도 다른 친구였다.
아래와 같은 코드를 볼 경우 aredra
는 개발자와 사람의 합집합으로 정의는 할 수 있지만 개발자, 사람 둘 중 하나로는 단정을 지을 수 없는 상태이다.
따라서 마지막 같은 코드에서 오류를 표기하게 된다.
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function getInfo(): Developer | Person {
return { name: "aredra", age: 99, skill: "TypeScript" };
}
const aredra = getInfo();
console.log(aredra.skill);
이에 대해 단언을 사용하면 사용이 가능하게 되지만 (aredra as Developer).skill
가독성이 떨어지기 때문에 이를 대체하는 것이 타입가드라는 친구이다.
위의 코드에 연달아 다음과 같이 사용이 가능하다.
function isDeveloper(target: Developer | Person): target is Developer {
return (target as Developer).skill !== undefined;
}
if (isDeveloper(aredra)) {
aredra.skill;
} else {
aredra.age;
}
보기는 하였지만 사실 이해가 안되는 부분이 있어 좀 더 공부를 해야될 것 같다. 아래 처럼 target is 빼고 쓰면 안되나? 써야하는 이유는? 그냥 스펙인가?? 🌀
function isDeveloper(target: Developer | Person): Developer {
return (target as Developer).skill !== undefined;
}
js로 변환해봐도 특이 사항은 없다… 생각을 좀 해보니 사실 return 자체 값은 boolean
이고 이 자체는 Developer
가 아니니 다르게 표현할 필요는 있을 것 같다.
"use strict";
function getInfo() {
return { name: "aredra", age: 99, skill: "TypeScript" };
}
const aredra = getInfo();
function isDeveloper(target) {
return target.skill !== undefined;
}
if (isDeveloper(aredra)) {
aredra.skill;
} else {
aredra.age;
}