본문 바로가기
Language/TypeScript

[TypeScript] 유니언 타입 (Union Type) 과 교차 타입 (Intersection Type)

by 썸머워즈 2022. 6. 2.
반응형

TypeScript의 유니언 타입과 교차 타입에 대해 알아보자.


Union Type

아마 타입 스크립트를 사용하다 보면 가장 흔하게 볼 수 있는 게 유니언 타입이 아닐까 생각이 든다.

타입명 그대로 유추해볼 수 있는데, 여러 타입들을 조합하여 사용하는 방법이다.

 

type Direction = 'left' | 'right' | 'up' | 'down';
const move = (direction: Direction) => {
  console.log(direction);
}
move('left');
move('right');

// error: '"leftRight"' 형식의 인수는 'Direction' 형식의 매개 변수에 할당될 수 없습니다.
move('leftRight');

이전 게시글에서 정리한 문자열 리터럴을 사용한 유니언 타입의 경우 아주 유용한데,

위 예제처럼 사용할 경우 Direction 타입인 경우에는 무조건 'left', 'right', 'up', 'down' 중에 하나만 사용해야 한다.

 

하지만 한 가지 문제점이 뭐냐면 우선 아래 예제를 살펴보자.

function printId(id: number | string) {
  console.log(id.toUpperCase());
  // string | number' 형식에 'toUpperCase' 속성이 없습니다.
  // 'number' 형식에 'toUpperCase' 속성이 없습니다.
}

이럴 경우 에러가 발생하는데, 이는 number 타입과 string 타입이 동시에 들어올 수 있기 때문에 string 메서드인 toUppercase()를 사용할 수 없다고 에러가 발생하는 것이다.

 

이럴 때는 좀 더 구체적으로 타입을 추론할 수 있게 도와줘야 하는데, 여러 방법이 존재하겠지만 몇 가지 방법만 예시를 통해 알아보자.

function printId(id: number | string) {
  if (typeof id === "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id);
  }
}

이런 식으로 타입을 구체적으로 추론할 수 있게 도와주기만 하면 정상적으로 작동한다.

 

물론 공통 메서드나 프로퍼티를 가지고 있다면 에러 없이 수월하게 사용할 수 있다.

function getFirstThree(x: number[] | string) {
  return x.slice(0, 3);
}

 

추가적으로 당연하게도 타입 별칭을 조합하는 것도 가능하다.

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
 
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;

 

Intersection Type

교차 타입은 유니언 타입과 관련이 있지만 사용 방법은 매우 다르다.

유니언 타입은 조합해서 사용한다고 하면 교차 타입은 여러 가지 타입을 결합해서 사용한다고 생각하면 된다.

 

유니언 타입과 교차 타입의 비교 예시를 통해 좀 더 자세히 알아보자.

type Common = {
  name: string,
  age: number,
  gender: string
}

type Animal = {
  howl: string
}

type Cat = Common & Animal;
type Dog = Common | Animal;

let dog: Dog = {
  howl: 'dogggg'
}
let cat: Cat = {
  age: 3,
  gender: 'C',
  name: 'CC',
  howl: 'cattttt'
}

유니언 타입을 보면 알겠지만 결국 Common 타입과 Animal 타입 둘 중 하나만 만족해도 되기 때문에 저렇게만 작성해도 정상 작동하는 반면,

교차 타입의 경우 타입의 "결합"이기 때문에 전부 맞춰줘야 한다.

 

그리고 둘의 또다른 차이점에 대해 알아보자면 아래 예제를 살펴보자.

type Animal1 = {
  howl: number;
};
type Animal2 = {
  howl: string;
};

type animal1 = Animal1 | Animal2;
type animal2 = Animal1 & Animal2;

let test1: animal1 = {
  howl: "animallll",
};

// error : 'number' 형식은 'never' 형식에 할당할 수 없습니다.
let test2: animal2 = {
  howl: 123
};

서로 다른 타입에 같은 키값을 가졌지만 할당된 타입이 다를 경우 유니언 타입과 교차 타입이 받아들이는 경우가 다르다.

 

유니언 타입의 경우 말 그대로 둘 중 하나면 나오면 되기 때문에 큰 문제가 없는 반면

교차 타입의 경우 동일한 키 값의 서로 다른 타입이 있는 경우 never 타입으로 바꿔버리는 것을 볼 수 있다.

 

이 것 외에도 뭐가 더 있을것 같기는 하지만 좀 조심해서 사용할 필요가 있다.


참고: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types

 

Documentation - Everyday Types

The language primitives.

www.typescriptlang.org

반응형


댓글

TOP