타입 가드를 사용하는 이유는 보통 fetch 로 union 타입의 데이터를 가져올때이다.
만약 API 호출로 받아온 데이터의 타입이 string인데 toFixed(n) 과 같은 메서드를 사용했을때 에러를 발생시킨다. 당연히 그 뒤에 오는 코드들도 실행되지 않으니 큰 문제가될 수 있다.
타입가드, 타입 좁히기할때 사용할 수 있는 방법으로는..
■ Primitive value check
- typeof : 원시값(string, number, boolean) 을 체크한다.
■ Reference value check
- instanceof : class only
■ Object's key name check
- key in obj : 객체에서 key 값이 있는지 확인
■ Object array check
- isArray : 배열
predicates 에서 predicate 란, 예측하다 또는 단정하다, 단언/선언하다라는 의미이다. 즉, 타입을 단정짓는것이라고 이해하면된다.
요즘 트렌드는 조건문 if 에 조건식을 함수로 넣는 것인데...
interface Adult {
type: 'adult';
age: number;
drinkAlcohol(): void;
}
interface Minor {
type: 'minor';
age: number;
drinkJuice(): void;
}
function isAdult(person: Adult | Minor): boolean {
return person.type === 'adult'
}
function drink(person: Adult | Minor): void {
if (isAdult(person)) {
person.drinkAlcohol(); // 타입스크립트가 정확히 추론하지 못해 drinkAlcohol 매서드 부분에 에러가 발생한다.
return;
}
person.drinkJuice(); // 여기도 마찬가지
}
함수 isAdult 에서 정확히 구분한뒤 boolean 값으로 만약 'adult' 일 경우 true, 아니면 false 를 반환할 수 있도록 함수의 리턴타입을 boolean 으로 했음에도, drink 함수에서는 정확하게 감지를 못해 객체의 매서드에 접근할 수 없는 것을 볼 수 있다.
정답부터 보자면...
function isAdult(person: Adult | Minor): person is Adult {
return person.type === 'adult'
}
이렇게 함수의 리턴타입을 boolean 으로 true 또는 false, 두 개의 선택지를 주는 것이 아니라, 단 하나의 결과만 보여주어 단순화하는 것이 요새 트렌드이다.
function isAdult(person: Adult | Minor): person is Adult {
return person.type === 'adult'
}
function isMinor(person: Adult | Minor): person is Minor {
return person.type === 'minor'
}
function drink(person: Adult | Minor): void {
if (isAdult(person)) person.drinkAlcohol();
if (isMinor(person)) person.drinkJuice();
// 또는
if (isAdult(person)){
person.drinkAlcohol();
return;
};
person.drinkJuice();
}
원시값인 경우: typeof
function numOrStr( a: number | string ){ }
위 함수는 매개변수로 숫자 또는 문자를 받을 수 있다.
function numOrStr( a: number | string ){
a.toFixed(1)
}
numOrStr( "123" ) // error
toFixed 매서드는 숫자에 대해서만 사용할 수 있는 매서드인데 만약 매개변수가 문자열일 경우 자바스크립트는 에러 메시지를 발생시킨다. 이러한 다중 데이터 타입을 수용하는 함수의 매개변수인 경우 타입가드(타입구분)를 통해 특정 타입에 대해서만 동작할 수 있도록 코드를 작성해야 한다.
function numOrStr( a: number | string ){ // 숫자 또는 문자
if(typeof a === "number"){
a.toFixed(1);
}
if(typeof a === "string"){
a.charAt(3);
}
}
numOrStr( "123" )
numOrStr( 123)
배열인 경우: isArray
function numOrNumArray(a: number | number[ ]){ // 숫자 또는 숫자 배열
if(Array.isArray(a)){
a.concat(4);
}
if(typeof a === "number"){
a.toFixed(1);
}
}
numOrNumArray(123);
numOrNumArray([1, 2, 3]);
클래스인 경우: instanceof
class A { aaa( ) { } }
class B { bbb( ) { } }
function aOrB( param: A | B ) { }
aOrB(new A)
aOrB(A) // error
aOrB 함수의 매개변수 A | B는 class A, class B 자체를 받는 것이 아니라 new A, new B 인스턴스를 받는다.
(★class는 타입으로 사용할 수 있다.)
function aOrB( param: A | B ) {
if( param instanceof A ){
param.aaa()
}
if( param instanceof B ){
param.bbb()
}
}
객체의 경우 속성과 속성값을 바탕으로 구분지을 수 있다.
type B = { type: "b", bbb: string };
type C = { type: "c", ccc: string };
type D = { type: "d", ddd: string };
속성값으로 구분
function typeCheck(a: B | C | D){
if(a.type === "b"){
a.bbb;
}
if(a.type === "c"){
a.ccc
}
if(a.type === "d"){
a.ddd
}
}
속성명으로 구분
function typeCheck(a: B | C | D){
if("bbb" in a){
a.bbb;
}
if("ccc" in a){
a.ccc;
}
if("ddd" in a){
a.ddd;
}
}
'TypeScript' 카테고리의 다른 글
제네릭 Generic (0) | 2024.06.05 |
---|---|
keyof, typeof, as const (0) | 2022.09.28 |
useEffect 안에서 useRef 사용 시 타이핑 (0) | 2022.09.24 |
[객체타입] readonly, 인덱스드 시그니처, 맵드 타입스 (0) | 2022.09.15 |
타입스크립트 공부 (0) | 2022.09.08 |
댓글