[TS] 타입 추론, 타입 단언, 타입 가드

작성:    

업데이트:

카테고리:

태그: , ,

본 포스트는 인프런의 타입스크립트 입문-기초부터 실전까지 강의(링크)를 듣고 정리한 내용입니다.


타입 추론(Type Inference)

타입 추론이란?

// parameter의 type으로 return 값의 type이 결정
function getB(b) {
  return b;
}
// parameter의 type으로 return 값의 type이 결정
function getB(b) {
  const c = 'hi'
  return b + c;
}
  • number + string = string으로 type 추론
  • return 값이 내부적으로 string으로 추론


인터페이스와 제네릭에서의 타입 추론

인터페이스와 제네릭

interface Dropdown<T> {
  value: T;
  title: string;
}

const shoppingItem: Dropdown<string> = {
  value: 'abc',
  title: 'hello',
}


인터페이스의 상속

interface Dropdown<T> {
  value: T;
  title: string;
}

// 관행적으로 T를 쓰지만 구분을 위해 K 사용
interface DetailedDropdown<K> extends Dropdown<K> {
  description: string
  tag: K;
}

const detailedItem: DetailedDropdown<string> = {
  value: 'abc',
  title: 'hello',
  description: '안녕하세요~~',
  tag: 'a'
}

인터페이스 A를 상속받은 인터페이스 B는 generic의 Type도 상속 가능


Best Common Type

배열 내에 type이 여러 종류가 있는 경우

const arr: (number | string | boolean)[] = [1, 2, 3, 'a', 'b', 'c', true];

유니온 타입을 이용해 배열에 들어간 개체들의 타입을 추론해 union type으로 정의

image


Typescript Language Server

  • Typescript 작성 중에 오류를 확인하기 위해 실시간으로 동작
  • VS Code의 IntelliSence가 동작하기 위해서도 사용


타입 단언(Type Assertion)

타입 단언의 필요성

let a;
a = 20;
a = 'a';
let b = a;
  • any였던 a가 중간의 코드를 거치며 type이 확정
  • 하지만 이후의 a를 참조하는 b는 a의 중간 코드를 모르므로, 처음에 선언했던 any type으로 지정


let a;
a = 20;
a = 'a';
let b = a as string;

image

  • “TS보다 개발자가 더 코드를 잘 알고 있다! 그러니 내가 지정한대로 해라!”
  • DOM API를 사용할 때 많이 사용


DOM API와 타입 단언

<div id="app">hi</div>
const app = document.querySelector('#app');
  • app의 type은 HTMLDivElement
  • 하지만 실무에서는 이렇게 깔끔하게 펼쳐지지 않는다.

image

  • HTMLDivElement일 수도 있지만 null 일 수도 있다는 의미!


HTMLDivElement임을 증명하자

const div = document.querySelector('div') as HTMLDivElement;
if (div) {
  div.innerText;
}
  • HTMLDivElement가 확실하다고 개발자가 전달
  • HTMLDivElement에서 지원하는 DOM API 사용 가능


타입 가드

타입 가드의 필요성

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

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

function introduce(): Developer | Person {
  return { name: 'Tony', age: 33, skill: 'Iron Making' }
}
  • 위의 두 interface로 정의된 introduce 함수의 반환값은 두 interface의 union type

image


  • tony는 name만 접근할 수 있다. 두 interface에 공통으로 존재하기 때문!
  • 반대로 생각하면 tony가 Developer interface인데 Person interface의 속성을 쓰면 안되기 때문


const tony = introduce();
if ((tony as Developer).skill) {
  const skill = (tony as Developer).skill;
  console.log(skill);
} else if ((tony as Person).age) {
  const age = (tony as person).age;
  console.log(age);
}
  • tony의 두 interface type에 대하여 타입 단언으로 있으나 없으나 사용
  • 없으면 if문에서 걸러지고, 있으면 if문 내부에서 사용 가능


좀 더러운데요?

  • 타입단언 코드도 반복되고 좀 더럽긴 하다.


타입 가드의 활용

function isDeveloper(target: Developer | Person): target is Developer {
  return (target as Developer).skill !== undefined;
}
  • Developer일지, Person일지 모르는 target을 전달받음
  • 이를 Developer로 간주하고 skill을 찍었을 때, Developer면 string, Person이면 undefined
  • 만약 true이면 target을 Developer로 한다.


위의 함수를 사용해보자.

// if ((tony as Developer).skill) {
//   const skill = (tony as Developer).skill;
//   console.log(skill);
// } else if ((tony as Person).age) {
//   const age = (tony as person).age;
//   console.log(age);
// }

if(isDeveloper(tony)) {
  console.log(tony.skill)
} else {
  console.log(tony.age)
}

댓글남기기