Type Narrowing-2(Type Predicate)

GI JUNG·2022년 12월 16일
3

typescript

목록 보기
3/10
post-thumbnail

primitive value든 reference value는 typescript에서 typeof 또는 instanceof 등등으로 type을 알아낼 수 있는 방법이 있다. 하지만, 내가 정의한 타입에 대해서는 typescript는 정의한 타입에 대한 검사만 해줄 뿐, 해당 타입인지 아닌 지 어떻게 검사하게 할까???🤔

이것에 대한 것이 type predicate(타입 명제)를 이용하면 된다.

🍀 Type Predicate(타입 명제)

내가 정의한 타입 Adult(성인)Minor(미성년자)에 대해서 drink라는 함수를 호출 했을 때 술을 마실 수 있냐 없냐에 대해서 code를 짜고 싶다고 가정하자.

// type definition
interface Adult {
  age: number;
  drinkAlcohol(): void;
}

interface Minor {
  age: number;
  drinkJuice(): void;
}

// variable initialization
const highSchoolStudent: Minor = {
  age: 14,
  drinkJuice: function () {
    console.log("Drink Juice!!!");
  },
};

const me: Adult = {
  age: 28,
  drinkAlcohol: function () {
    console.log("Drink Alcohol");
  },
};

이제 정의한 타입에 대해서 타입좁힘을 이용하여 아래와 같이 type에 맞게 적절한 함수를 호출하고 싶다.

function drink(person: Adult | Minor): void {
  if 어른이라면 -> dirnkAlcohol함수 호출
  if 미성년자라면 -> drinkJuice함수 호출
}

어른인지 아닌지에 대허서 typescript에게 알려주기 위해서는 isAdult라는 타입검사 함수를 별도로 작성해야 한다.

// get type is Adult or not
function isAdult(person: Adult | Minor) {
  return (person as Adult).drinkAlcohol !== undefined;
}

// wanna invoke drink function depends on Adult or Minor
function drink(person: Adult | Minor): void {
  if (isAdult(person)) {
    person.drinkAlcohol();
    return;
  }

  person.drinkJuice();
}

drink(me);   // 'Drink Alcoho'이 나오길 예상

isAdult를 이용해서 typescript가 type narrowing을 통해 type을 검사할 수 있을지 알았지만 아래와 같은 오류가 나온다. Adult 또는 Minor 둘 중에 대해서 drinkAlcohol property가 있을 수 없다는 내용이다.
즉, typescript는 내가 전달한 me라는 변수가 Adult인지 Minor인지 모른다.....😭😭😭

이를 해결하기 위해서는 명확하게 isAdult가 return하는 값이 Adult type이라는 것을 [parameter name] is Adult 를 이용하여 명시해 주어야한다.
따라서 다시 isAdult라는 함수로 가보자

function isAdult(person: Adult | Minor): person is Adult {   // 👈 Adult를 return하는 것을 명시
  return (person as Adult).drinkAlcohol !== undefined;
}

이제는 isAdult가 true를 반환한다면 typescript는 Adult type이구나!!! 하면서 알아들을 것이다. 이와 반대로 false라면 Adult type이 아님이 된다.

자 이제 잘 돌아가는지 전체 코드를 살펴보자
entire code


interface Adult {
  age: number;
  drinkAlcohol(): void;
}

interface Minor {
  age: number;
  drinkJuice(): void;
}

function isAdult(person: Adult | Minor): person is Adult {
  return (person as Adult).drinkAlcohol !== undefined;
}

function drink(person: Adult | Minor): void {
  if (isAdult(person)) {
    person.drinkAlcohol();
    return;
  }

  person.drinkJuice();
}

const highSchoolStudent: Minor = {
  age: 14,
  drinkJuice: function () {
    console.log("Drink Juice!!!");
  },
};

const me: Adult = {
  age: 28,
  drinkAlcohol: function () {
    console.log("Drink Alcohol!!!");
  },
};

drink(highSchoolStudent);   // "Drink Juice!!"
drink(me);   // "Drink Alcoho!!!"

전체코드에서 adult로 type narrowing을 진행하면 adult type properties들이 자동완성 기능으로 제공된다.!!!🥳

원하는 결과가 잘 출력된다!!

🎉 마치며

custom type에 대해서는 어떻게 type을 좁힐 수 있지 의문을 가지게 되었다가 해결하고자 알아보게 됐다. 이전 포스트에서 typescript docs를 통해 공부하고 있었는데 배울 내용이 많기 때문에 필요한 부분만 배우려고 했다. 따라서 instanceof narrowing까지만 봤는데.... 궁금한 것에 검색할 필요도 없이 바로 아래 3번째 목차에 using type predicate이라고 있었다....😭😭😭 하지만, 여기서 느낀 점은 type predicate만 보고서 custom type검사에 관한 것이라고는 생각을 못했다. 아는만큼 보인다고.... 내가 알고자 하는 것이 딱 명칭이 되어있다면 그 명칭을 모르면 찾아보기가 힘들다....
예를 들어 그냥 원시적으로 생각하여 재사용 가능한 어떤 입력에 대해서 원하는 로직을 통해 원하는 결과를 뱉어주는 것이 뭘까???라고 생각들었을 때 How to get the value that i wanted depending on the input value that has been processed라고 검색하지 않을까?
하지만, 이는 공부한 입장에서 함수임을 안다. 알기 전까지 궁금한 것을 해소하기 위해서는 검색을 해야하는 것을 더 깨닫게 되는 순간이다. 사실상 검색을 해야하는 것은 알지만 어떻게? 잘? 검색하는 것이 중요한 것 같다.
""를 이용하면 무조건 포함 시키고 -를 이용하면 원하지 않는 내용을 제외하는 것은 알고 있지만 더 검색을 잘하기 위해 한 번 찾아봐야겠다!!

📚 참고

type predicate by techblog
using type predicate

profile
step by step

0개의 댓글