솔미는 성장중

[TS] 타입 가드 본문

TypeScript

[TS] 타입 가드

solming 2023. 8. 30. 22:59
728x90

💻 타입 가드

여러  개의 타입으로 지정된 값을 특정 위치에서 원하는 타입으로 구분하는 것

 

💻 타입 가드가 필요한 이유

-/-예를 들어 number | string | boolean 타입으로 지정되어있다면 세 타입 모두에서 사용할 수 있는 속성과 API만 접근 가능하다. 즉, toUpperCase, toFixed() 등의 메소드를 사용할 수 없다.

 

해결 방법)

1. 타입 가드 사용하기 (다음 섹션에서 자세히 설명)

 

2. 타입 단언으로도 해당 문제를 해결 가능

//예시
function updateInput (textInput: number | string | boolean) {
  (textInput as number).toFixed(3);
}

하지만 문제점!
- 실행 시점의 에러를 막을 수 없다.

- 타입 단언을 계속해서 사용해야 한다 (반복적인 코드)

 

 

💻 사용하는 주요 연산자

typeof

if문과 함께 사용해 타입 가드 역할을 수행할 수 있다.

//함수 내에서
if( typeof textInput === 'number'){
  //~~내용~~;  
  return;
}
if( typeof textInput === 'string'){
  //~~내용~~;  
  return;
}

 

instanceof 

변수가 대상 객체의 프로토타입 체인에 포함되어있는지 확인해 true/false 반환

  연산자 작동방식)

function User(name,age){
this.name=name;
this.age=age;
}

let person1 = new  Person('솔미', 100);
person1 instanceof User; // true

let person2 = {name: '철수', age: 90);
person2 instanceof User; // false

  instanceof로 타입 가드)

function fetchIfoByProfile(profile: Person | string){
  if(profile instanceof Person){
    //여기 안에선 profile타입이 Person 타입으로 간주됨
  }
}

 

in

객체에 특정 속성이 있으면 true, 없으면 false

in 연산자를 이용해 인터페이스 2개가 유니언 타입으로 연결되어 있을 때 특정 인터페이스로 구분 가능

(단, 특정 속성이 두 인퍼테이스 모두에 있으면 특정 타입으로 구분해 주지 않는다. = 타입 가드 역할 X)

function fetchIfoByProfile(profile: Person | Image){
  if('url' in profile){
    //url은 Image란 interface내에만 있는 속성이었음.
    //그래서 이 블록 안에서는 profile의 타입이 Image로 간주됨.
  }
}

 

💻 타입 가드 함수

주로 객체 유니언 타입 중 하나를 구분하는 데 사용. (in 연산자와 유사. but 복잡한 경우에도 사용 가능)

 

예시) 두 인터페이스에서 공통으로 갖고 있는 속성명.(age) 하지만 다른 속성값.(하나는 number, 다른 하나는 string)
         특정 인터페이스에서의 속성을(age:number) 출력하고 싶다면?

 

interface Hero{
  name:string;
  nickname: string;
}
interface Person{
  name:string;
  age: number;
}
interface Developer{
  name:string;
  age: string;
  skill: string;
}

function isPerson(someone: Hero | Person | Developer): someone is Person {
  return typeof (someone as Person).age === 'number';
}

function greet(someone: Hero | Person | Developer){
  if(isPerson(someone)){
   console.log(someone.age);  //Person타입으로 추론. age속성 타입은 number가 된다.
  }
}

 

 

💻 구별된 유니언 타입

유니언 타입을 구성하는 여러 개의 타입을 특정 속성 유무가 아니라 특정 속성 값으로 구분하는 타입 가드 문법

 

예제)

interface Person {
  name: string;
  age:number;
  industry: 'common';
}
interface Developer {
  name: string;
  age:string;
  industry: 'tech';
}

function greet(someone: Person | Developer) {
  if(someone.industry === 'common') {
    //someone의 타입은 Person 타입으로 추론됨.
  }
}

 

industry 속성에 문자열 타입이 각각 common과 tech로 선언되어서 구분가능 했다. 

 

 

💻 switch 문과 연산자

앞선 예제를 수정)

interface Person {
  name: string;
  age:number;
  industry: 'common';
}
interface Developer {
  name: string;
  age:string;
  industry: 'tech';
}

function greet(someone: Person | Developer) {
  switch(someone.industry) {
    case 'common':
      //someone의 타입은 Person 타입으로 추론됨.
      break;
    case 'tech':
      //someone의 타입은 Developer 타입으로 추론됨.
      break;
  }
}

 

 

💻 논리 비교 연산자

function sayHi(message: string | null){
  if(message && message.length >=3){ //message값이 있는지를 확인해주면서 타입 가드 적용 효과
    console.log(message);
  }
}
////////////////////////////////////////
//같은 기능 다른 방식 : ! 사용하기
function sayHi(message: string | null){
  if(message!.length >=3){ //null아님 보장 연산자를 이용해 string타입으로만 간주되게.
    console.log(message);
  }
}
//같은 기능 다른 방식 : if구문으로 null 걸러주기
function sayHi(message: string | null){
  if(message === null){ //null일 땐 그냥 반환
    return;
  }
  if(message.length >=3){ 
    console.log(message);
  }
}
728x90