타입스크립트 (4) - 타입 가드란? what is Type Guard in TypeScript?
😼 타입 가드 (Type Guard)를 사용하면 조건문을 통해 타입을 좁혀나갈 수 있다.
이를 잘 활용하면 가독성과 생산성이 좋은 코드가 될 수 있다고 하니 어떻게 사용하는지 기록해둘 것이다.
typeof 를 사용한 타입 가드
Primitive 타입일 경우 typeof Type Guard을 주로 사용한다. 예시는 다음과 같다.
function getNumber (value: number | string): number {
value; // number | string
if (typeof value === "number") {
value; // number
return value;
// typeof type guard에서 타입 하나를 리턴할 경우 해당 타입으로는 더이상 추론되지 않습니다.
}
value; // string
return -1;
}
-> 위 예제를 보면 typeof로 조건문을 걸어주는 것을 통해 타입을 좁혀 나가는 것을 확인할 수 있다 🙌
instanceof 를 사용한 타입가드
instanceof를 이용한 타입가드는 주로 Error 객체를 구분할 때 많이 쓰인다고 하는데, 예제를 살펴보자.
class NegativeNumberError extends Error {}
function getNumber(value: number): number | NegativeNumberError {
if (value < 0) return new NegativeNumberError();
return value;
}
function main() {
const num = getNumber(-10); // 에러를 반환하지 않습니다.
if (num instanceof NegativeNumberError) {
return; // num이 NegativeNumberError의 인스턴스일 경우 return
// typeof num === "object"이므로 typeof를 쓸 경우 정확한 타입가드를 할 수 없음
}
num; // number
}
-> 위 예제를 보면 첫번째 예제에서 본 typeof로 타입을 좁혀 나가는 방식과 유사한 것 같지만 instanceof를 사용했다.
이유는 주석을 보자! 🙀
in 을 사용한 타입가드
in을 객체의 프로퍼티 유무로 조건문을 사용할 수 있다. 예제를 살펴보자.
interface Admin {
id: string;
role: string:
}
interface User {
id: string;
email: string;
}
function redirect(user: Admin | User) {
if("role" in user) {
routeToAdminPage(user.role); // Admin
} else {
routeToHomePage(user.email); // User
}
}
-> 프로퍼티 유무를 통해 타입을 좁혀나가는 것을 확인할 수 있다.
literal type의 타입가드
리터럴 값의 경우 === / == / !== / != 연산자를 사용해 타입을 구분할 수 있다. 예제를 살펴보자.
type TriState = 'yes' | 'no' | 'unknown';
function logOutState(state:TriState) {
if (state == 'yes') {
console.log('사용자가 yes를 골랐습니다');
} else if (state == 'no') {
console.log('사용자가 no를 골랐습니다');
} else {
console.log('사용자가 아직 결정을 내리지 않았습니다.');
}
}
-> 위 코드는 이해하기가 쉽다 😃
유니온 타입에 리터럴 타입이 있는 경우도 있는데 동일하게 적용하면 된다. 예제를 보자.
type Foo = {
kind: 'foo', // 리터럴 타입
foo: number
}
type Bar = {
kind: 'bar', // 리터럴 타입
bar: number
}
function doStuff(arg: Foo | Bar) {
if (arg.kind === 'foo') {
console.log(arg.foo); // 성공
console.log(arg.bar); // 에러 발생
}
else {
console.log(arg.foo); // 에러 발생
console.log(arg.bar); // 성공
}
}
-> 위 코드의 경우 Foo, Bar 타입에 각각의 literal type의 property가 있어 이를 조건문으로 비교하여 타입가드한 것을 확인할 수 있다.
Custom으로 만드는 타입가드
Type Guard를 커스텀하게 작성하여 적용할 수도 있다. 예제는 다음과 같다.
function getWhellOrMotor(machine: any): number {
if (isCar(machine)) {
return machine.wheel; // machine은 Car 타입이 된다
} else if (isBoat(machine)) {
return machine.motor; // machine은 Boat 타입이 된다
} else {
return -1;
}
}
// Custom Type Guard
function isCar(arg: any): arg is Car {
return arg.type === 'CAR';
}
function isBoat(arg: any): arg is Boat {
return arg.type === 'BOAT';
}
-> arg is Car : 함수의 반환값이 true일 경우 arg의 타입이 Car로 적용되는 것을 의미한다.
이번 포스팅에는 타입 가드를 간략하게 정리해두었다.
다음 포스팅에는 tsconfig에는 어떤 옵션을 적용할 수 있는지 기록해 둘것이다.
재밌는 타입스크립트...😇