[TypeScript] 타입 가드

종현·2024년 1월 4일

[TypeScript]

목록 보기
12/19

타입 가드란?

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

  • 넓은 타입에서 좁은 타입으로 타입 범위를 좁힌다는 의미로 볼 수 있다.

  • if문을 사용하여 타입 가드 역할을 하고, if문 안에서는 타입이 string이기 때문에 string에 대한 API를 미리 자동 완성으로 사용할 수 있다.

function updateInput(text: number | string | boolean) {
  // 타입 가드
  if (typeof text === 'string') {
    text~~ // (parameter) text: string
  }
}

타입 가드가 필요한 이유

  • 아래 코드는 유니언 타입으로 정의되어 있기 때문에 해당 타입의 API를 사용하려 하면 에러가 발생하게 된다.

    • ex) text가 number타입일때 text.toFixed(2);를 사용하려 하면 에러가 발생하고, 지정된 모든 타입에서 사용할 수 있는 속성과 API만 접근할 수 있다.
function updateInput(text: number | string | boolean) {
    text~~ // (parameter) text: number | string | boolean
}

타입 단언으로 에러 해결하기

  • as키워드를 사용하여 text의 타입을 number로 단언한다.

    • 해당 에러가 사라지고, 자동 완성도 가능하게 된다.
function updateInput(text: number | string | boolean) {
  (text as number).toFixed(2);
}

타입 단언을 사용했을 때 문제점

  • 타입 에러는 해결되지만, 두 가지의 문제가 발생한다.

    • 실행 시점의 에러는 막을 수 없다.

    • 타입 단언을 계속 사용해야 한다.

    • number타입 API인 toFiexd를 사용하고 string타입 API인 length를 사용하기 위해서 as키워드를 반복적으로 사용해야 한다.

function updateInput(text: number | string | boolean) {
  (text as number).toFixed(2);
  
  console.log((text as string).length)
}

타입 가드로 에러 해결하기

  • if문을 사용하여 타입 가드를 사용한다.

    • text의 타입이 number일때만 number타입 API를 사용하고, string일때만 string타입 API를 사용할 수 있다.
function updateInput(text: number | string | boolean) {
  if (typeof text === 'number') {
    text.toFixed(2);
    
    return;
  }
  
  if (typeof text === 'string') {
    console.log(text.length);
    
    return; 
  }
}

타입 가드 문법

  • 타입 가드에 주로 사용하는 연산자

    • typeof

      • 연산자 뒤에 붙은 값의 타입을 반환해준다.

      • if문과 함께 사용하여 특정 위치에서 원하는 타입으로 구분할 수 있다.

    const name = 'jonghyun';
    
    if (typeof name === 'string') {
      ...
    }
    • instanceof

      • 변수가 대상 객체의 프로토타입 체인에 포함되는지 확인하여 true / false를 반환해준다.

      • 주로 클래스 타입이 유니언 타입으로 묶여 있을 때 타입을 구분하기 위해 사용한다.

    class Person {
      name: string;
      age: number;
    
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    }
    
    function getProfile(profile: Person | string) {
      if (profile instanceof Person) {
        profile.name~~~
        profile.age~~~
      }
    }
    • in

      • 객체에 특정 속성이 있으면 true, 없으면 false를 반환해준다.

      • 인터페이스 2개가 유니언 타입으로 연결되어 있을 때 특정 인터페이스로 구분할 수 있다.

      • 같은 속성을 가진 인터페이스는 타입 가드 역할을 할 수 없다.

        • name의 경우 두 인터페이스 모두 가지고 있으므로 타입 가드의 역할을 할 수 없다.

        • 둘중의 하나만 가지고 있는 속성을 통해서만 타입 가드의 역할을 할 수 있다.

      interface Book {
        name: string;
        rank: string;
      }
      
      interface Online {
        name: string; 
        url: string;
      }
      
      function learnCourse(material: Book | Online) {
        if ('url' in material) {
        // 이 블록 안에서는 material이 Online 타입으로 간주된다.
        }
      }

타입 가드 함수

  • isPerson함수는 Me, Person, Developer의 유니언 타입을 파라미터로 받고, Person타입인지 아닌지 결과 값으로 반환해준다.

  • is키워드를 사용할 수 있고, is뒤에 붙은 타입의 속성을 확인 한 후 해당 속성이 존재한다면 해당 타입으로 간주하라는 의미이다.

interface Me {
  name: string;
  nickName: string;
}

interface Person {
  name: string;
  age: number;
}

interface Developer {
  name: string; 
  age: string;
  skill: string;
}

// 타입 가드 함수
function isPerson(someone: Me | Person | Developer): someone is Person {
  return typeof (someone as Person).age === 'number'
}

function getAge(someone: Me | Person | Developer) {
  if (isPerson(someone)) {
    console.log(someone.age);
  }
}

구별된 유니언 타입

  • 같은 속성을 가진 인터페이스에 구별이 가능한 다른 특정 값을 가지고 있을 경우 조건문에 해당하는 값을 가지고 있는 인터페이스의 타입으로 정의된다.
interface Person {
  name: string;
  age: number;
  industry: 'common';
}

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

function getIndustry(someone: Person | Developer) {
  if (someone.industry === 'tech') {
    someone // (parameter) someone: Developer
  }
}

switch 문과 연산자

  • if문 말고도 switch문이나 비교 / 논리 연산자로도 적용할 수 있다.

switch 문

  • switch문을 사용하여 industry값을 비교하고 해당하는 타입을 someone에 정의하여 해당 타입의 속성에 대한 API와 자동 완성을 사용할 수 있다.
interface Person {
  name: string;
  age: number;
  industry: 'common';
}

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

function getIndustry(someone: Person | Developer) {
  switch (someone.industry) {
    case 'common':
      console.log(someone.age.toFixed(2));
      break;
    case 'tech': 
      console.log(someone.age.length);
      break;
  }
}

논리 / 비교 연산자

  • 파라미터 타입이 string과 null의 유니언 타입인데 null체크를 하여 null이 아닐때만 message를 출력해줄 수 있다.

  • null아님 보장 연산자(!)를 사용할 수도 있다.

function sayHello(message: string | null) {
  if (message === null) return;
  
  if (message.length >= 3) {
    console.log(message)
  }
}

function sayHello(message: string | null) {  
  if (message!.length >= 3) {
    console.log(message)
  }
}
  • 위의 코드들 대신에 &&연산자(논리 / 비교 연산자)를 사용하여 타입 가드를 할 수 있다.

  • &&연산자는 양쪽의 모든 항이 true여야 하기 때문에 null체크와 동시에 타입 단언을 사용하지 않고 타입 가드를 할 수 있다.

function sayHello(message: string | null) {  
  if (message && message.length >= 3) {
    console.log(message)
  }
}

출처: 쉽게 시작하는 타입스크립트

profile
지속 가능한 성장 습관을 만들어 나가고 싶어요!

0개의 댓글