ํ์ ๊ฐ๋(Type Guard)
๋ฐฐ์ธ ๊ฐ๋
intersection Type
union Type
Type Guard
1. ๋ฌธ์ ๋ฐ์
interface Animal {
eat: () => void;
sleep: () => void;
}
class Dog implements Animal {
eat() {}
sleep() {}
}
class Cat implements Animal {
eat() {}
sleep() {}
}
Dog
ํด๋์ค์ bark()
๋ฉ์๋๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์๋ฐ?
- ๊ทธ๋ฌ๊ธฐ ์ํด์ ,
Animal
์ธํฐํ์ด์ค์bark()
๋ฅผ ์ถ๊ฐํด์ผํ๊ณ ,Animal
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋Cat
ํด๋์ค๋bark()
๋ฉ์๋๋ฅผ ๊ตฌํํด์ผํ๋ ๋นํจ์จ์ด ๋ฐ์ํ๋ค. - ํด๋น ํ์ ์ ์ฐ๋ ๋ชจ๋ ์ฝ๋์ ๋ณ๊ฒฝ์ ๊ฐํ์ง ์๊ณ , ํน์ ์ฝ๋๋ง ์์ ๋กญ๊ฒ ํ์ ์ ํ์ฅํ๋ ๋ฐฉ๋ฒ ์์๊น?
2. Intersection Type
A & B
: A ํ์ ์ด๋ฉด์ B ํ์
type Human = {
think: () => void,
};
type Developer = {
work: () => void,
};
const junha: Human & Developer = {
think() {
console.log(`I'm thinking`);
},
work() {
console.log(`I'm working`);
},
};
์ธ์ ์ฌ์ฉํด?
Intersection Type
์ ๊ธฐ์กด ํ์ ์ ๋์ฒดํ์ง ์์ผ๋ฉด์, ์๋ก์ด ํ๋๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์ ๋ ์ฌ์ฉ
type Human = {
think: () => void;
};
type Developer = {
work: () => void;
};
type Rich = {
flex: () => void;
};
const junha: Human & Developer & Rich = {
think() {
console.log(`I'm thinking`);
},
work() {
console.log(`I'm working`);
},
flex() {
console.log(`I'm flexing`);
},
};
- ๊ธฐ์กด์
Human
&Developer
ํ์ ์ junha์Rich
ํ์ ์ ์ถ๊ฐํด ๊ธฐ์กด ํ์ ์ ๋ณ๊ฒฝํ์ง ์๊ณ ํ์ฅํ ์ ์๋ค.
์ฃผ์!! ๊ฐ ํ์ ์ ๊ฒน์น๋ ํ๋๊ฐ ์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
- intersection ํ๋ ค๋ ๋ ํ์ ์ ํ๋๊ฐ ๋ค๋ฅด๋ค๋ฉด ์ค๋ฅ๋ฅผ ์ถ๋ ฅํ๋ค.
// develop ๋ฉ์๋ ์ ์ธ, ๋งค๊ฐ๋ณ์๋ ์๊ณ , ๋ฐํ ํ์
์ void์ด๋ค
type Developer = {
develop: () => void;
};
type Designer = {
design: () => void;
};
const ๊ฐ์์ด๋: Developer & Designer = {
develop() {
console.log("I'm programming");
},
design() {
console.log("I'm designing");
},
};
๊ฐ์์ด๋.develop(); // I'm programming ์ถ๋ ฅ
๊ฐ์์ด๋.design(); // I'm designing ์ถ๋ ฅ
3. Union Type
A | B
: A ํ์ , B ํ์ ๋ ์ค ํ๋
let one: string | number;
one = '1';
one = 1;
์ธ์ ์ฌ์ฉํด?
- ์ฌ๋ฌ ํ์ ์ค ํ๋๊ฐ ์ฌ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ ๋ ์ฌ์ฉํ๋ค.
- ํ์ง๋ง ์ธํฐํ์ด์ค๋ ์ ๋์จ ํ์ ์ ํ์ฅํ์ง ๋ชปํ๋ค.
- ์ด๋๋
type
ํค์๋์&
(Intersection Type)์ ์ฌ์ฉํด ํ์ฅํ๋ค.
type A = string | number;
interface StrOrNum extends A {
a: string;
}
// error An interface can only extend
// an object type or intersection of object types with statically known members.
type StrOrNum = {
a: string;
} & (string | number);
// Ok
์ฃผ์!! Union Type์ ๋์์ ์ฌ๋ฌ ํ์ ์ด ๋ ์ ์๋ค.
type Human = {
think: () => void;
};
type Dog = {
bark: () => void;
};
declare function getType(): Human | Dog;
const junha = getType();
junha.think(); // Property 'think' does not exist on type 'Dog'.
junha.bark(); // Property 'bark' does not exist on type 'Human'.
junha
์ ํ์ ์ ์ ๋์ธ ํ์ ์ผ๋ก ์ ์ธ๋์๊ธฐ ๋๋ฌธ์, Human์ธ์ง Dog์ธ์ง ํ์ ํ ์ ์๋ค.- ๋ฐ๋ผ์
think
,bark
๋ ์ค ์ด๋ ๋ฉ์๋๋ ์ฌ์ฉํ์ง ๋ชปํ๋ค. junha.think()
ํจ์๋ฅผ ํธ์ถํ ๋ junha๊ฐHuman
์ด๋ผ๋ฉด ๊ด์ฐฎ์ง๋งDog
๋ผ๋ฉด think๋ฅผ ํธ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ์ปดํ์ผ ๋จ๊ณ์์ ์๋ฌ๊ฐ ๋์จ๋ค.- ์ด ์๋ฌ๋
ํ์ ๊ฐ๋
๋ฅผ ํตํด ํด๊ฒฐํ ์ ์๋ค.
4. Type Guard
1) ํ์ ๊ฐ๋๋?
- ๋ฐ์ดํฐ์ ํ์ ์ ์ ์ ์๊ฑฐ๋, ๋ ์ ์๋ ํ์ ์ด ์ฌ๋ฌ ๊ฐ๋ผ๊ณ ๊ฐ์ ํ ๋, ์กฐ๊ฑด๋ฌธ์ ํตํด ๋ฐ์ดํฐ์ ํ์ ์ ์ขํ๋๊ฐ๋ ๊ฒ์ ๋งํ๋ค.
- ๋ฐ์ดํฐ์ ํ์ ์ ๋ฐ๋ผ ๋์ํ์ฌ ์๋ฌ๋ฅผ ์ต์ํํ ์ ์๋ค.
- ํ์ ์ ํตํด ‘๊ฐ๋’ํ๋ ์ฝ๋, ๋ฐฉ์ด์ ์ธ ์ฝ๋๋ฅผ ์งค ์ ์๋ค.
2) ํ์ ๊ฐ๋๋ฅผ ์ฌ์ฉํด ์ ๋์ธ ํ์ ์ ์ ๋๋ก ์ฌ์ฉํด๋ณด์
type Human = {
think: () => void;
};
type Dog = {
tail: string;
bark: () => void;
};
declare function getType(): Human | Dog;
const junha = getType();
// here is the clue
if ('tail' in junha) {
junha.bark();
} else {
junha.think();
}
3) What happend?!
- ํ์
์คํฌ๋ฆฝํธ์๊ฒ ํ์
์ ์ถ๋ก ํ ์ ์๋๋ก
๋จ์
๋ฅผ ์ฃผ์๋ค! - ์ด๋ ๊ฒ ํ์ ์ ๊ตฌ๋ณํ ์ ์๋ ๋จ์๊ฐ ์๋ ์ ๋์จ ํ์ ์ ๊ตฌ๋ณ๋ ์ ๋์จ๋ผ๊ณ (ํ๊ทธ๋ ์ ๋์จ, ์๋ก์ ์ ๋์จ)ํ๋ค.
4) ์ค๋ฌด์์ ์์ฃผ ์ฐ๋ ๊ตฌ๋ณ๋ ์ ๋์จ๊ณผ ํ์ ๊ฐ๋
type SuccessResponse = {
status: true;
data: any;
};
type FailureResponse = {
status: false;
error: Error;
};
type CustomResponse = SuccessResponse | FailureResponse;
declare function getData(): CustomResponse;
const response: CustomResponse = getData();
if (response.status) {
console.log(response.data);
} else if (response.status === false) {
console.log(response.error);
}
- ์๋ฒ์์ ์ค๋ ์๋ต ๋๋ ํจ์์ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฌ ๊ฐ๋๋ก ๋๋ ๋ ๊ตฌ๋ณ๋ ์ ๋์จ ์ฌ์ฉ ๊ฐ๋ฅ
- ํ์ ์ ๋จ์๋ฅผ ํ ๋๋ก ํ์ ๊ฐ๋๋ฅผํ๊ณ , ์๋ต์ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ๋ค๋ฅธ ์์ ์ ์คํ์์ผ์ค๋ค.
5) ๋ค์ํ ์ฐ์ฐ์๋ฅผ ํตํ ํ์ ๊ฐ๋
01. instanceof
- ํด๋์ค๋ ํ์ ์ด๋ค. ๊ฐ์ฒด๊ฐ ์ด๋ค ํด๋์ค์ ๊ฐ์ฒด์ธ์ง ๊ตฌ๋ณํ ๋ ์ฌ์ฉํ๋ ์ฐ์ฐ์
์ธ์คํด์ค instanceof ํด๋์ค
์ ๊ฐ์ด ์ฌ์ฉํ๋ค.
class Developer {
develop() {
console.log(`I'm working`);
}
}
class Designer {
design() {
console.log(`I'm working`);
}
}
const work = (worker: Developer | Designer) => {
if (worker instanceof Designer) {
worker.design();
} else if (worker instanceof Developer) {
worker.develop();
}
};
02. typeof
- ๋ฐ์ดํฐ์ ํ์ ์ ๋ฐํํ๋ ์ฐ์ฐ์
typeof ๋ฐ์ดํฐ === 'string'
๊ณผ ๊ฐ์ด ์ฌ์ฉtypeof ๋ฐ์ดํฐ === 'undefined'
์ฒ๋ผundefined
์ฒดํฌ๋ ๊ฐ๋ฅ- ์ฐธ๊ณ ๋ก
๋ฐ์ดํฐ == 'null'
๊ณผ ๊ฐ์ด ์ฐ๋ฉดnull
,undefined
๋ ๋ค ์ฒดํฌ
const add = (arg?: number) => {
if (typeof arg === 'undefined') {
return 0;
}
return arg + arg;
};
03. in
key in obj
:obj.key
์ ์กด์ฌ์ฌ๋ถ ๋ฆฌํด
type Human = {
think: () => void;
};
type Dog = {
tail: string;
bark: () => void;
};
declare function getType(): Human | Dog;
const junha = getType();
if ('tail' in junha) {
junha.bark();
} else {
junha.think();
}
04. literal type guard
- ๋ฆฌํฐ๋ด ํ์ : ํน์ ํ์ ์ ํ์ ํ์ . ๊ตฌ์ฒด์ ์ธ ํ์ . string ํ์ ์ ๋ฆฌํฐ๋ด ํ์ ์ ‘cat’, ‘dog’
- ๋ฆฌํฐ๋ด ํ์
์ ๋๋ฑ
(==)
, ์ผ์น(===)
์ฐ์ฐ์ ๋๋switch
๋ก ํ์ ๊ฐ๋ ๊ฐ๋ฅ - ์ฐธ๊ณ ๋ก ์์ ์ฒ๋ผ ํ๋์ value ๊ฐ์ ๋ฐ๋ผ ์กฐ๊ฑด๋ฌธ์ ์์ฑํ๋ ๊ฒฝ์ฐ, ๋๋ถ๋ถ์ ๊ฒฝ์ฐ switch์ ์ฐ์ฐ ๊ฒฐ๊ณผ๊ฐ if-else๋ณด๋ค ๋ ๋น ๋ฅด๋ฏ๋ก ๋๋๋ก switch๋ฅผ ์ฐ๋ ๊ฑธ ๊ถ์ฅํด ๋๋ฆฝ๋๋ค. ์กฐ๊ฑด๋ฌธ์ ๊ฐ์๊ฐ ์ ์ผ๋ฉด ํฐ ์ฐจ์ด๋ ์์ง๋ง, ์กฐ๊ฑด๋ฌธ์ ๊ฐ์๊ฐ ๋ง์์ง์๋ก switch์ ์ฑ๋ฅ์ด ๋ ๋น ๋ฅด๋ค.
type Action = 'click' | 'hover' | 'scroll';
const doPhotoAction = (action: Action) => {
switch (action) {
case 'click':
showPhoto();
break;
case 'hover':
zoomInPhoto();
break;
case 'scroll':
loadPhotoMore();
break;
}
};
const doPhotoAction2 = (action: Action) => {
if (action === 'click') {
showPhoto();
} else if (action === 'hover') {
zoomInPhoto();
} else if (action === 'scroll') {
loadPhotoMore();
}
};
05. ์ฌ์ฉ์ ์ ์ ํจ์
import is from '@sindresorhus/is';
const getString = (arg?: string) => {
if (is.nullOrUndefined(arg)) {
return '';
}
if (is.emptyStringOrWhitespace(arg)) {
return '';
}
return arg;
};
- type guard์ ์ ์ฉํ ์คํ์์ค ์ค
sindresorhus/is
๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ
๋ ์ฑ ์๊ฒ ํ์ ์ ์ฒดํฌํ ์ ์๋ค. Yarn add @sindersorhus/is
,npm install @sindersorhus/is
๋ฐ์ํ