[TS] 리터럴 타입 / 유니온 타입 / 교차 타입

정(JJeong)·2023년 2월 2일
0

TypeScript 익히기

목록 보기
6/10
post-thumbnail

이전 공부과정에서 슬쩍슬쩍 사용해보며 넘어갔던 여러 타입 정의 방법들을 한 번 알아보자.

📌 Literal Type(리터럴 타입)

Literal Type을 알기 위해 먼저 예시를 하나 보고 가자.

const name1 = "Bob";
let name2 = "Tom";

위 코드에서 각 변수명에 마우스를 갖다대 보면 각 타입이 어떻게 뜰까?


1) name1은 const선언

선언 방식에 주목해보면 된다. name1의 경우 const로 선언, 즉, 변하지 않는 값을 선언할 때 사용한다.
그렇기 때문에 name1의 타입은 "Bob"으로 뜬다. 'Bob'외의 값은 가질 수 없기 때문이다.


2) name2는 let선언

그렇다면 name2는 어떨까? 이미 눈치챘겠지만 변할 수 있는 값을 선언하는 let을 썼기 때문에 보다 넓은 범위로써 string이라는 타입이 뜬다.

그리고 이때 string으로써 정해지기 때문에 name2 = 3과 같이 string이 아닌 값으로 재할당하려 하면 경고가 뜬다.
최초할당 값에 의해 타입이 결정되었기 때문이다.

만약 number도 원하면 명시적으로 첫 선언때 작성해주어야 한다.

let name2: stirng | number = "Tom";


위 예시를 통해 두가지 선언방식이 TS에서 어떻게 작동하는지 보았고, 동시에 리터럴 타입을 맛보았다.
음? 리터럴 타입이 어디에 있느냐? 바로 const!

위의 const처럼 정해진 string값을 가진 것을 Literal Type이라고 한다.



type으로 리터럴 타입 지정하기

문자열 리터럴 타입 지정

이는 전에 먼저 정보 좀 찾고 훑던 과정에서 정리했던 적이 있으니 이전 글을 참고하면 좋을 것 같다.

간단 예시를 보여주자면,

type Job = 'Developer' | 'Cook' | 'Police'

interface User {
  name: string,
  job: Job
}

위와 같고 해당 인터페이스로 만드는 객체의 job값은 세가지 값만 가능해진다.

숫자열 리터럴 타입 지정

숫자열이라고 해서 특별히 다를 것은 없다.

type Rank = 1 | 2 | 3 | 4

interface Player {
  name: string,
  rank: Rank
}

위처럼 작성하면 rank에 들어올 값은 1, 2, 3, 4 중 하나가 되어야 한다.



📌 유니온 타입(|)

앞서 공부하는 과정에서 자연스레 쓴 |라는 기호가 있는데 이것이 유니온 타입이다. 즉, 연산자라 볼 수 있다.

사용하면서 눈치껏 느끼기에 경우를 구분지어주는 or의 의미같다. 마치 JS에서 OR연산자로 ||를 쓰는 것과 같은데, 이건 한 줄만 쓰네?

뭐 여하튼! 단순히 |로 나누는게 유니온 타입이다~ 하고 끝낼 것이 아니라 이것의 장점을 알아보자.

유니온 타입의 장점

대충 any쓸래!의 불상사

먼저 여러가지 타입이 올 수 있으니 대~충 any로 타입을 지정했을 때를 가정해보자.

function getAge(age: any) {
  age.toFixed(); // 에러 발생
  return age;
}

위 예시 코드를 보면 age의 타입이 any로 추론되기 때문에 설사 age가 숫자라 하더라도 자동적으로 JS의 숫자 관련 메소드를 자동완성하지 않는다.

TS playground에서는 any로 해도 자동완성이 모두 뜨길래 '음?'싶었는데 편집기에서 찍어보니까 다음처럼 차이가 있다.

타입을 명확히 TS에 알려주면 이에 따라서 작성하고자 하는걸 추론해 자동완성을 제공한다.

왜냐하면 age에 어떤 값이 들어올 지 typescript에서는 단정지을 수 없으니까.

때문에 any로 작성하면 typescript의 이점을 누릴 수 없다. JS로 작성하는 것과 다름없기 때문.

위 경우엔 그저 number로 타입을 작성해주면 되지만 만약 타입이 여러 종류 가능할 경우엔 어떻게할까?
이럴때 유니온 타입으로 타입을 명시화해주면 된다.


유니온 타입의 활용

function getAge(age: number | string) {
  if (typeof age === 'number') {
    age.toFixed();
    return age;
  }
  if (typeof age === 'string') {
    return age;
  }
  return new TypeError('age must be number or string');
}

위 코드에선 age로 들어오는 값의 타입을 유니온 타입을 통해 number와 string이 들어올 수 있다고 알려주었다.

그리고 이를 if문에서 확인하여 들어온 값을 식별해 분기를 나눴다.
그렇기 때문에 첫번째 if문에서는 number로 확인된 age만 실행되어 수와 관련된 api 추론이 가능해진다.

아래 string의 경우 if문엔 특별히 api를 안썼지만 이 경우에도 마찬가지로 쓰고자할 때 추론이 가능하다. 유니온 짱짱

한줄 정의: 동일 속성의 타입을 구별하여 식별 가능하도록 하는 것이 유니온 타입이다.



📌 교차 타입(intersection type)

교차타입은 여러 개의 타입을 합쳐서 사용한다. 위의 유니온이 OR의 의미였다면 이는 AND의 의미라고 할 수 있다.

interface Car {
  name: string,
  start(): void
}

interface Toy {
  name: string,
  color: string,
  price: number
}

const toyCar: Toy & Car = {
  name: "Benz",
  color: "blue",
  start() {console.log("GO!")},
  price: 30000
}

위에서 Toy와 Car라는 타입을 &을 이용해 합쳐주어 교차 타입으로 사용해주었다.
이렇게 만들어진 toyCar변수는 위 타입 두가지의 속성을 모두 지녀야한다.


음.. 쓰면서 interface의 확장 기능인 extends와 교차타입 중 어떤 것이 상황에 따라 유리한지 잘 생각하며 코드를 짜야겠다.

참고: interface확장에 대해 정리했던 글

끄읕!



profile
2년차 응애 FE 개발자입니다👶

0개의 댓글