
타입 가드란 여러 개의 타입으로 지정된 값을 특정 위치에서 원하는 타입으로 지정하는 것을 의미합니다.
예를 들어, string, number, boolean 타입을 가지고 있는 변수를 어떤 지점에서 string 타입만 갖게끔 만드는 것입니다. 다시 말해 타입을 좁히는(Narrowing) 것입니다.
이를 코드로 표현하면 다음과 같습니다.
function onlyString(inputs: string | number | boolean) {
// 타입 가드
if (typeof inputs === 'string') {
console.log(inputs);
}
}
onlyString 함수에 string 타입이 들어올 때만 inputs가 출력됩니다.typeof 연산자는 코드의 타입을 문자열로 반환합니다.
function printText(text: string | number) {
text.trim(); // Error
}
string과 number 타입을 갖는 인자를 받아와 trim 메서드를 실행하였습니다.trim 메서드를 실행하면 에러가 발생합니다.trim 메서드는 string 타입에서만 실행되는 메서드이기 때문입니다. 위의 코드에서는 text 변수가 string 타입일 수도 있지만 number 타입일 수도 있기 때문에 에러가 발생합니다.function printText(text: string | number) {
if (typeof text === 'string') {
console.log(text.trim());
}
if (typeof text === 'number') {
console.log(text.toFixed(2));
}
}
typeof 연산자로 text 변수의 타입이 string일 때와 number일 때로 나누었습니다.text 변수가 string 타입으로 추론되어 trim 메서드를 사용할 수 있습니다.text 변수가 number 타입으로 추론되어 toFixed 메서드(Number.prototype.toFixed())를 사용할 수 있습니다.in 연산자는 객체에 특정 속성이 있으면 true, 특정 속성이 없으면 false를 반환합니다.
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
return animal.swim(); // Error
}
Fish 타입은 swim 속성을 가지고 있고, Bird 타입은 fly 속성을 가지고 있습니다.Fish 타입이나 Bird 타입을 갖는 animal을 인자로 받습니다.swim()을 실행하면 에러가 발생합니다.swim()은 Fish 타입만 갖고 있는 속성인데, animal은 Fish 타입일 수도 있지만 Bird 타입일 수도 있기 때문입니다.type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
return animal.swim();
}
return animal.fly();
}
in 연산자로 animal에 swim 속성이 있는지 확인하고 있으면(true면) swim()을 실행하고, 없으면 fly()를 실행합니다.instanceof 연산자는 변수가 대상 객체의 프로토타입 체인에 포함되면 true, 포함되지 않으면 false를 반환합니다.
예를 들어, x instanceof Foo는 x의 프로토타입 체인에 Foo.prototype이 포함되어 있는지 확인합니다.
function logValue(x: Date | string) {
console.log(x.toUTCString()); // Error
}
Date 타입이나 string 타입을 갖는 x를 인자로 받습니다.x.toUTCString()을 실행하면 에러가 발생합니다.toUTCString()은 Date 타입만 갖고 있는 속성인데, x는 Date 타입일 수도 있지만 string 타입일 수도 있기 때문입니다.function logValue(x: Date | string) {
if (x instanceof Date) {
console.log(x.toUTCString());
}
else {
console.log(x.toUpperCase());
}
}
instanceof 연산자로 x가 Date의 프로토타입 체인에 포함되면 x는 Date 타입으로 추론되어 x.toUTCString()가 실행되고, 포함되지 않으면 x는 string 타입으로 추론되어 toUpperCase()가 실행됩니다.타입스크립트에서는 ===, !==, ==, != 으로 동등성을 체크하여 타입 가드를 하기도 합니다.
function example(x: string | number, y: string | boolean) {
if (x === y) {
x.toUpperCase();
y.toLowerCase();
} else {
console.log(x);
console.log(y);
}
string 타입이나 number 타입을 갖는 x와 string 타입이나 boolean 타입을 갖는 y를 인자로 받습니다.x와 y가 같다면 둘의 타입도 같기 때문에 if문이 true이면 x와 y는 string 타입이 됩니다.false이면 x는 string이나 number 타입이 될 것이고, y는 string이나 boolean 타입이 됩니다.구별된 유니언 타입(discriminated uinons)이란 유니언 타입을 구성하는 여러 개의 타입을 특정 속성 값으로 구분하는 타입 가드 문법을 의미합니다.
interface Haikyuu {
name: string;
year: number;
genre: 'sports';
}
interface Titan {
name: string;
year: string;
genre: 'action';
}
function animation(ani: Haikyuu | Titan) {
if ('year' in ani) {
console.log(ani);
}
}
name, year, genre 속성을 가지고 있는 Haikyuu 인터페이스와 Titan 인터페이스가 있습니다.Haikyuu 인터페이스나 Titan 인터페이스를 타입으로 갖는 ani를 인자로 받습니다.Haikyuu와 Titan은 속성의 이름이 모두 같기 때문에 in 연산자로 타입 가드를 할 수 없습니다. function animation(ani: Haikyuu | Titan) {
if (ani.genre === 'action') {
console.log(ani);
}
}
genre 입니다. genre가 action일 때로 구분하면 ani는 Titan 타입으로 추론됩니다.참고
📖 쉽게 시작하는 타입스크립트
🔗https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking