유니온 타입을 통해 여러 타입을 가진 형태를 표현할 수 있었다
하지만 특정 타입을 가질때만 로직을 실행해야 하는 경우에 유니온 타입은 도움이 되지 못한다
이렇게 넓은 타입을 더 좁은 타입으로 재정의 하는 것을 타입 좁히기 라고 한다
주로 명확하지 않은 타입이 있을 때 사용하며 말그대로 타입을 좁혀나가는 과정이다
특정한 스코프 내에서 타입 좁히기를 유발하는 표현을 타입 가드(Type Guard)라고 한다
특정 조건이 만족될 때에만 코드를 실행하거나 같은 코드를 여러번 실행하는 식으로
순차적 실행을 벗어난 실행을 가능하게 한다
if, else if, else
while, for
switch, case
break, continue
return
문자열, 숫자, 불리언과 같은 원시 값 처리할 때 주로 사용한다
조건문과 typeof
키워드를 사용하여 원시값을 체크할 수 있다
function printTriple(value: number | string) {
// 조건문으로 value의 타입이 string인지 판별
if (typeof value == 'string') {
return value.repeat(3); // value: string
}
return value * 3; // value: number
}
console.log(printTriple('hi')); // 'hihihi'
null
, undefined
, falsy
값을 좁히거나 제거할 수 있다
// EX1
const thing = document.getElementById('idk');
if (thing) {
thing; // thing: HTMLElement
} else {
thing; // thing: null
}
// EX2
const printLetters = (word?: string) => {
if (word) {
for (let char of word) { // word: string
console.log(char);
}
} else {
// word : string | undefined (truthy인지 falsy인지 확인만 하기 때문에)
console.log('YOU DID NOT PASS IN A WORD!');
}
}
printLetters('HI'); // H // I
printLetters(); // YOU DID NOT PASS IN A WORD!
비교 연산자 =
를 사용하여 값을 좁혀나간다
이중등호 ==
를 사용할 경우 "3"과 3을 같다고 인식해 타입체킹이 제대로 일어나지 않는다
반드시 삼중등호 ===
를 사용하여 타입까지 판별할 것!
function equality(x: string | number, y: string | boolean) {
if (x === y) {
console.log(x.toUpperCase()); // x: string, y: string
}
}
equality(3, '3');
equality('abc', 'abc'); // ABC
A in B
👉🏻 A(프로퍼티)가 B에 존재하는지 판별한다
in
연산자를 활용하면 특정 프로퍼티가 인터페이스나 타입별칭 내에 있는지 판별할 수 있다
✏️ in
을 주로 사용하는 경우
① typeof를 사용할 수 없는 경우
② 인터페이스나 타입별칭을 활용해 객체로 작업하는 경우
// EX1)
const pet = { name: 'Kitty', age: 20 };
console.log('name' in pet); // true
console.log('age' in pet); // true
console.log('legs' in pet); // false
// EX2)
interface TVShow {
title: string;
episodes: number;
episodeDuration: number;
}
interface Movie {
title: string;
duration: number;
}
function getRuntime(media: TVShow | Movie) {
let runtime;
if ('episodes' in media) {
// media: TVShow
runtime = media.episodes * media.episodeDuration;
} else {
// media: Movie
runtime = media.duration;
}
console.log(`${media.title} : ${runtime}분`);
}
getRuntime({ title: '더문', duration: 129 }); // 더문 : 129분
getRuntime({ title: '더글로리', episodes: 16, episodeDuration: 60 }); // 더글로리 : 960분
A instanceof B
👉🏻 A(객체)가 B(클래스)에 존재하는지 판별한다
instanceof
연산자를 활용하면 객체(A)가 어떤 클래스(B)인지, 어떤 클래스를 상속받았는지(B)를 판별할 수 있다
✏️ instanceof
를 주로 사용하는 경우
① typeof
를 사용할 수 없는 경우
② new
키워드를 사용해 초기화한 클래스 등으로 작업하는 경우
// EX1)
function printFullDate(date: string | Date) {
if (date instanceof Date) {
// date: Date
console.log(`Date : ${date.toUTCString()}`);
} else {
// date: string
console.log(`String : ${new Date(date).toUTCString()}`);
}
}
printFullDate(new Date()); // Date : Thu, 24 Aug 2023 08:42:18 GMT
printFullDate('Thu, 24 Aug 2023 GMT'); // String : Thu, 24 Aug 2023 00:00:00 GMT
// EX2)
class User {
constructor(public username: string) {}
}
class Company {
constructor(public companyname: string) {}
}
function printName(person: User | Company) {
if (person instanceof User) {
// person: User
console.log(`UserName : ${person.username}`);
} else {
// person: Company
console.log(`CompanyName : ${person.companyname}`);
}
}
const user = new User('jan');
printName(user); // UserName : jan
const company = new Company('네이버');
printName(company); // CompanyName : 네이버
parameterName is Type
parameterName as Type
타입스크립트에만 있는 기능으로
함수(isXXX)를 직접 정의하여 TypeScript에게 XXX의 타입이 무엇인지를 알려준다
타입명제는 해당 함수의 타입으로 작성되어야 한다
interface Cat {
name: string;
age: number;
}
interface Dog {
name: string;
leg: number;
}
// isXXX 형태의 함수를 직접 정의
// ↳ Cat의 속성이 있다면 true, 없다면 false를 반환
function isCat(animal: Cat | Dog): animal is Cat {
// (animal is Cat) → true를 반환한다면 Cat 타입이다
return (animal as Cat).age !== undefined;
// (animal as Cat) → animal이 Cat임을 단언, Cat의 속성을 사용
}
function makeNoise(animal: Cat | Dog): string {
if (isCat(animal)) {
animal; // animal: Cat
return 'Meow~~';
} else {
animal; // animal: Dog
return 'BowWow!';
}
}
const cathy: Cat = { name: 'Cathy', age: 4 };
console.log(makeNoise(cathy)); // Meow~~
const max: Dog = { name: 'Max', legs: 1 };
console.log(makeNoise(max)); // BowWow!
모든 타입의 공통된 프로퍼티에 판별자를 추가하여 타입을 판별한다
① 공통된 프로퍼티를 공유하는 여러 타입을 생성하고
② 해당 프로퍼티에 리터럴 값을 할당하여 사용한다
공통 프로퍼티는 하나만 있어도 가능하다
// 공통 프로퍼티 : kind
interface Rooster {
name: string;
weight: number;
age: number;
kind: 'rooster';
}
interface Cow {
name: string;
weight: number;
age: number;
kind: 'cow';
}
interface Pig {
name: string;
weight: number;
age: number;
kind: 'pig';
}
type FarmAnimal = Pig | Rooster | Cow;
function getFarmAnimalSound(animal: FarmAnimal) {
switch (animal.kind) {
case 'rooster':
animal; // animal: Rooster
return '꼬끼오';
case 'cow':
animal; // animal: Cow
return '음메';
case 'pig':
animal; // animal: Pig
return '꿀꿀';
}
}
const stevie: Rooster = {
name: 'Stevie',
weight: 3,
age: 2,
kind: 'rooster',
};
console.log(getFarmAnimalSound(stevie)); // 꼬끼오