리코딩 : 타입스크립트(TypeScript)

타입스크립트 - 타입 가드(Type Guard)

BreezeBm 2021. 10. 20. 23:07

출처 : 구글 이미지

지난시간에 기록했던 것을 연장해서 기록해보자!

function add10(val: string | number) {
  return val + 10;
}

변수를 넣으면 10을 더해주는 함수가 있다고 가정해보자. 뭔가 이상한 점이 있다. 바로 변수가 string인 경우이다. 변수에 숫자가 아닌 문자열이 오면 에러가 발생한다. 그렇기 떄문이 타입가드가 쓰인다. 타입가드를 사용하지 않으면 에러가 발생하는데, 타입가드를 사용함으로써 이러한 에러를 줄일 수 있다.

01. typeof

typeof를 사용해서 원시타입을 검사한다. typeof를 사용하면 타입을 문자열로 반환해서, 이걸 가지고 검사를 한다.

function add50(x: string | number){
  console.log(x + 50);
}

add50("100"); // 문자열과 숫자를 더할 수 없기 떄문에 에러를 발생
add50(100);

function add100(x: string | number) {
  if (typeof x === "string") {
    console.log(Number(x) + 100);
  }
  console.log(x);
}

add100("100");
add100(100);

add50에 변수로 문자열을 주게 되면 에러를 발생한다. 문자열과 숫자를 더할 수 없기 떄문이다. 그래서 typeof를 사용해서 문자열인 경우에는 문자열을 숫자로 변경해서 값을 더하는 연산을 처리해야한다.

02. instanceof

class객체를 식별할 때 instanceof를 사용한다. 생성자 함수가 반환하는 클래스의 경우에는 typeof를 사용하면 모든 객체가 'object'를 반환하기 때문이다.

 

class Human {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  hello() {
    console.log(`Hello, ${this.name}`);
  }
}

class Robot {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  hi() {
    console.log(`Hi, ${this.name}`);
  }
}

const human = new Human("GEE");
const robot = new Robot("æXXX");

function something(arg: Human | Robot) {
  if (arg instanceof Human) {
    return arg.hello();
  } else {
    return arg.hi();
  }
}

something(human);
something(robot);

Human이라는 클래스에 hello()라는 메서드가 있다. 그래서 instanceof를 사용해서, Hyman이라는 클래스가 변수로 들어오는 경우에는 hello()라는 메서드를 실행을 시키고, 아닌 경우에는 hi()메서드를 실행을 시킨다.

03. in

타입스크립트로 객체를 정의하는 경우 class말고도 interface로 정의하기도 한다. in을 사용해서 프로퍼티 비교를 통해서 타입을 검증할 수 있다.

interface Bird {
  fly(): void;
}

interface Fish {
  swim(): void;
}

function act(animal: Bird | Fish) {
  if ("fly" in animal) {
    animal.fly();
  } else {
    animal.swim();
  }
}

act함수에 변수로 들어오는 인터페이스에 따라서 각각의 인터페이스가 가지고 있는 메서드를 실행시킨다.

04. 사용자 정의 가드

위에 작성했던 가드 말고도 사용자가 직접 타입을 확인하는 함수를 작성해서 사용이 가능하다. value is Typed 형태의 반환타입을 갖는 함수로 정의한다. 

function isFish(animal: Fish | Bird): animal is Fish {
  return (animal as Fish).swim !== undefined
}

Fish 타입을 검사 하는 함수를 작성해따. 이 함수는 불리언 타입을 반환한다. 다른 함수에서 사용해서 조건문을 통해 특정 타입을 검사하게 된다. 

interface Bird {
  leg: 2;
  fly(): void;
}

interface Fish {
  spin: boolean;
  swim(): void;
}

// bird => true
function isFish(animal: Fish | Bird): animal is Fish {
  return (animal as Fish).swim !== undefined;
}

function doSomething(animal: Fish | Bird) {
  if (isFish(animal)) {
    animal.swim();
  } else {
    animal.fly();
  }
}

어떻게 생각하면 타입가드를 작성하는 것도 정말 귀찮을 수 있지만, 계속해서 느끼는 점은 귀찮게 느껴지는 몇줄이 나중에는 정말 큰힘을 발휘하는 것 같다... 공부.. 공부..