유니온 (Union)

Changhan·2025년 1월 21일

Typescript

목록 보기
7/29

유니온은 조금 복잡한 타입을 구성할 수 있는 기능이라고 생각하면 된다. 다른 말로 타입을 병합할 수 있는 수많은 방법 중 하나다.

타입을 병합할 수 있는 방법은 많지만 유니온을 이용해 병합하는 경우가 제일 많고, 유니온이 필요한 로직이 굉장히 많다.

그러므로 유니온이 어떻게 동작하는지 정확하게 아는 것이 중요할 것이다!!


다음 예제를 보자.

type StringOrBooleanType = string | boolean;
let stringOrBooleanType: StringOrBooleanType = '태연';
stringOrBooleanType = true;

stringOrBooleanType 변수의 값의 타입은 string 혹은 boolean 둘 중 하나면 되므로 '태연'이 들어가도 문제가 없다.
그리고 이 변수를 boolean 타입인 true로 변경을 해도 문제가 없을 것이다.

그런데 여기서 만약에 undefined를 넣게 되면?

stringOrBoolenaType = undefined;

당연히 에러가 날 것이다. string 또는 boolean 타입이 아니기 때문이다.


그렇다면 지금까지는 2개의 타입을 가질 수 있는 타입을 만들었는데 그 이상도 만들 수 있을까?

3가지 타입을 가져야 하는 타입을 만들어 보자.

type StrBoolNullType = string | boolean | null;

이 또한 가능하고, 이 뒤에 무한히 추가할 수 있다!


type StateType = 'DONE' | 'ERROR' | 'LOADING';
state = 'LOADING'; // O
state = 'INITIAL'; // X

유니온으로 여러 개의 값들을 입력할 수 있고, 이 이외의 값은 입력할 수 없도록 만들 수가 있다는 것을 기억하자!
타입을 제한하거나 값을 제한하거나 원하는 값들의 영역만 입력할 수 있도록 만들 수 있는 굉장히 유용한 기능이다!!


리스트의 유니온에 대해서 살펴보자.

type StringListOrBooleanList = string[] | boolean[];

let stringListOrBooleanList: StringListOrBooleanList = [
  '태연',
  '권나라',
  '윤아',
]; // O

let stringListOrBooleanList: StringListOrBooleanList = [
  true,
  false,
  true,
]; // O

let stringListOrBooleanList: StringListOrBooleanList = [
  '태연',
   true,
  '윤아',
]; // X

우리가 선언한 StringListOrBooleanList 타입에서 세 번째 예시는 올바르지 않다. 왜냐면 string으로만 구성된 리스트 혹은 boolean으로만 구성된 리스트여야 하기 때문이다.

세 번째 코드와 같이 리스트 하나에 여러 타입을 넣고 싶다면?

type StringOrNumber = (string | nmber)[];

let stringOrNumber: StringOrNumber = [
  1, 2, 3, '태연'
];
stringOrNumber = [
  11, 12, 13
];
stringOrNumber = [
  '태연', '윤아', '권나라'
];

괄호 안에 넣고 싶은 타입을 넣어주면 된다. 또는 숫자만 넣어도 되고, 문자열만 넣어도 된다.


interface로 사용하는 유니온

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

interface Human {
  name: string;
  age: number;
  address: string;
}

이 두 가지 타입을 가지고 유니온으로 구성해보자.

type AnimalOrHuman = Animal | Human;

let animalOrHuman: AnimalOrHuman = {
  name: '권나라',
  age: 32,
  address: '대한민국',
};

여기서 Human 타입이라 가정하고, 프로퍼티를 입력했다. 그러면 타입스크립트도 내가 Human 타입을 입력한 것을 알고 있는지 확인해보자.

console.log(animalOrHuman);

타입을 확인하면 Animal | Human 타입이 아니라 Human 타입인 걸 확인할 수 있다.
이것을 타입스크립트가 어떻게 추론을 했을까? Human 타입이 되려면 address 프로퍼티가 있어야 한다. address 프로퍼티가 있으면 무조건 Human 타입이다. 그래서 address를 입력하면 자동으로 Human으로 추론한다.

다른 예제를 살펴보자.

animalOrHuman = {
  name: '모서리',
  age: 8,
};
console.log(animalOrHuman);

이것의 타입은 Animal 이다. 왜냐하면 address 프로퍼티가 없기 때문에 Animal 타입으로 추론한다.

console.log(animalOrHuman.name); // '모서리'
console.log(animalOrHuman.age); // 8
console.log(animalOrHuman.address); // X

위에서 이미 animalOrHumanAnimal 타입으로 추론이 되었다. 그래서 address 프로퍼티는 존재할 수 없다는 것을 타입스크립트는 이미 알고 있다.


그러면 타입을 선언해서 유니온으로 형성하는 것이 좋은 이유를 알아보자.

let animalOrHuman2: {
  name: string;
  age: number;
} | {
  name: string;
  age: number;
  address: string;
} = {
  name: '권나라',
  age: 32,
  address: '대한민국',
};
console.log(animalOrHuman2.name); // 권나라
console.log(animalOrHuman2.age); // 32
console.log(animalOrHuman2.address); // 대한민국

이렇게 직접적으로 객체를 타입으로 선언하고, 각 프로퍼티를 출력하면 정상적으로 출력이 될 것이다.

animalOrHuman2 = {
  name: '오리',
  age: 6,
};
console.log(animalOrHuman2.name);
console.log(animalOrHuman2.age);
console.log(animalOrHuman2.address); // X

추가적으로 animalOrHuman2의 값을 위와 같이 변경하고, 출력을 하게 되면 address 프로퍼티에서 에러가 발생한다.

첫 번째 사진과는 표시된 내용이 다른 것을 볼 수 있다. 두 번째 사진에는 타입의 이름이 가독성이 떨어져서 읽기가 쉽지 않다. 그래서 웬만하면 type 키워드를 이용해 타입을 형성한 다음에 선언을 하는 것이 에러를 파악하는 데 유용하다.


위의 예제에서는 두 개의 타입이 공통된 프로퍼티를 가지고 있었다. 하지만 만약에 아예 프로퍼티가 다른 두 타입을 유니온으로 선언한다면?

type Person = {
  name: string;
  age: number;
};
type Cat = {
  breed: string;
  country: string;
};
type PersonOrCat = Person | Cat;

const personOrCat: PersonOrCat = {
  name: '권나라',
  age: 32,
}; // O, type: PersonOrCat

const personOrCat2: PersonOrCat = {
  breed: 'Yorkshire Terrier',
  country: 'England',
}; // O, type: PersonOrCat
const personOrCat: PersonOrCat = {
  name: '권나라',
  age: 32,
  breed: 'Yorkshire Terrier',
  country: 'England',
};

유니온의 재밌는 점은 Person과 Cat의 프로퍼티 모두 다 넣어도 괜찮다는 점이다. 유니온과 뒤에 배울 인터섹션은 집합의 개념으로 보면 좋다. 바로 합집합의 개념이다.

위의 코드에서 Cat의 일부분인 country나 breed만 빼도 된다. 마찬가지로 위의 코드에서 Person의 일부분인 name나 age 중 하나만 빼도 된다.
그런데 Person에서 하나, Cat에서 하나를 지우는 것은 안된다. 무언가 타입의 하나는 충족되어야 한다는 것이다!

다음 포스팅에서는 인터섹션에 대해서 알아보자.

0개의 댓글