Typescript 개념잡기(5)

오형근·2022년 5월 16일
0

Typescript

목록 보기
5/15
post-thumbnail

저번 시간에 이어서 연산자를 이용한 타입 정의에 대해 공부해보자.

타입스크립트 핸드북(타입스크립트 핸드북)을 보고 공부한 것을 정리한 글입니다.
기본적인 JS 지식은 가진 상태라고 가정합니다.


Union Type

유니온 타입이란 자바스크립트의 OR 연산자(||)와 같이 A이거나 B이다 라는 의미의 타입이다. 아래 예제를 살펴보자.

function logText(text: string | number) {
  // ...
}

위 함수의 파라미터 text에는 문자열 타입이나 숫자 타입이 모두 올 수 있다. 이처럼 | 연산자를 사용해 타입을 여러 개 연결하는 것을 유니온 타입 정의 방식이라고 부른다.

Union Type의 장점

유니온 타입의 장점은 아래 2개의 코드를 비교하면 바로 알 수 있다.

// any를 사용하는 경우
function getAge(age: any) {
  age.toFixe(); // 에러 발생, age의 타입이 any로 추론되기 때문에 숫자 관련된 API를 작성할 때 코드가 자동 완성되지 않는다.
  return age;
}

// 유니온 타입을 사용하는 경우
function getAge(age: number | string) {
  if(typeof age === 'number') {
    age.toFixed(); // 정상 동작, age의 타입이 `number`로 추론되기 때문에 숫자 관련된 API를 쉽게 자동완성 할 수 있다.
    return age;
  }
  if(typeof age === 'string') {
    return age;
  }
  return new TypeError('age must be number or string');
}

이처럼 any를 사용하는 경우 마치 자바스크립트로 작성하는 것처럼 동작을 하고 유니온 타입을 사용하면 타입스크립트의 이점을 살리면서 코딩이 가능하다.

타입스크립트를 통해 타입 추론을 하면 자동완성이 되므로 코드 작성에서 오류 발생 가능성이 현저히 낮아진다!!

Intersection Type

인터섹션 타입은 여러 타입을 모두 만족하는 하나의 타입을 의미한다. 아래 예제를 살펴보자.

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

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

type Capt = Person & Developer;

위 코드는 Person 인터페이스의 타입 정의와 Developer 인터페이스 타입 정의를 & 연산자를 이용하여 합친 후 Capt라는 타입에 할당한 코드이다. 결과적으로 Capt의 타입은 아래와 같이 정의된다.

{
  name: string;
  age: number;
  skill: string;
}

이처럼 & 연산자를 이용해 여러 개의 타입 정의를 하나로 합치는 방식을 인터섹션 타입 정의 방식이라고 한다.

Union Type을 쓸 때 주의할 점

앞에서 유니온 타입과 인터섹션 타입을 살펴보았다. 아마 논리적으로 유니온 타입은 OR, 인터섹션은 AND라고 생각할텐데, 인터페이스와 같은 타입을 다룰 때에는 이런 논리적 사고를 주의해야한다.

아래 코드를 살펴보자.

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

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

function introduce(someone: Person | Developer) {
  someone.name; // O 정상 동작
  someone.age; // X 타입 오류
  someone.skill; // X 타입 오류

여기서 introduce() 함수의 파라미터 타입을 Person, Developer 인터페이스의 유니온 타입으로 정의하였다. 유니온 타입은 A도 될 수 있고 B도 될 수 있는 타입이지라고 생각하면 파라미터 타입이 Person도 되고 Developer도 될테니까 함수 안에서 당연히 이 인터페이스들이 제공하는 ageskill을 사용할 수 있겠지라고 생각할 수 있다. 그러나, 타입스크립트 관점에서는 파라미터에 Person이 올지 Developer 타입이 올지 알 수가 없기 때문에 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론하게 된다.

const capt: Person = { name: 'capt', age: 100 };
introduce(capt); // 만약 `introduce` 함수 안에서 `someone.skill` 속성을 접근하고 있으면 함수에서 오류 발생
const tony: Developer = { name: 'tony', skill: 'iron making' };
introduce(tony); // 만약 `introduce` 함수 안에서 `someone.age` 속성을 접근하고 있으면 함수에서 오류 발생

결과적으로 introduce() 함수 안에서는 별도의 타입 가드(Type Guard)를 이용하여 타입의 범위를 좁히지 않는 이상 기본적으로는 PersonDeveloper 두 타입에 공통적으로 들어이쓴 속성인 name만 접근할 수 있다.

function introduce(someone: Person | Developer) {
  console.log(someone.name); // O 정상 동작

지금까지 연산자를 이용한 타입 정의에 대해 알아보았다.

조금 당연해보이지만 그냥 넘어갈 수 없는 부분이므로 잘 숙지하도록 하자.

profile
https://nohv.site

0개의 댓글