유니언 타입 (Union Types)
TypeScript에서 유니언 타입은 하나의 값이 여러 타입 중 하나일 수 있음을 표현한다.
집합 이론에서의 합집합(A ∪ B) 개념과 동일하며, | 기호를 사용한다.
🧩 대수 타입(Algebraic type)이란?
대수 타입은 여러 개의 타입을 조합해서 새로운 타입을 만드는 방식을 말한다.
TypeScript에서는 대표적으로 Union Type과 Intersection Type이 있다.
Union Type: 여러 타입 중 하나를 허용하는 타입Intersection Type: 여러 타입을 모두 만족해야 하는 타입
1. 기본 사용법
유니언 타입을 정의할 때는 파이프 | 기호를 사용해 여러 타입을 나열한다.
let userId: string | number;
userId = 1;
userId = '1';
userId = true; // Error
userId = {}; // ErroruserId는 string 또는 number 타입만 허용한다.
따라서 boolean이나 객체는 할당할 수 없다.
함수의 매개변수에도 유니언 타입을 사용할 수 있다.
// 함수
function printUserId(id: string | number) {
console.log(id);
}
printUserId('1');
printUserId(1);
printUserId({}); // Error2. Type Narrowing (타입 좁히기)
유니언 타입은 여러 타입이 가능하기 때문에, 값을 사용할 때는 실제 타입을 확인해야 하는 경우가 많다.
이처럼 조건문 등을 사용해 타입을 더 구체적으로 좁히는 것을 타입 좁히기(Type Narrowing)라고 한다.
function processValue(value: number | string) {
if (typeof value === 'string') {
// 문자열인 경우
return value.toUpperCase();
}
// 숫자인 경우
return value.toString().toUpperCase();
}typeof: 런타임에서 타입 체크toString(): 숫자를 문자열로 변환toUpperCase(): 문자열 메서드
value는 처음에는 number | string 타입이다.
하지만 typeof value === 'string' 조건문 안에서는 TypeScript가 value를 string 타입으로 판단한다.
그래서 문자열 메서드인 toUpperCase()를 사용할 수 있다.
3. 배열에 유니언 타입 적용
유니언 타입은 배열 요소에도 적용할 수 있다.
let mixedValues: (string | number)[] = [];
mixedValues.push('100');
mixedValues.push(100);
mixedValues.push(true); // Error
mixedValues.push([]); // Error(string | number)[]는 배열의 각 요소가 string 또는 number일 수 있다는 뜻이다.
비슷해 보이지만 아래 두 타입은 의미가 다르다.
let mixedArray: (string | number)[] = ['hello', 1, 'world', 2];
let stringOrNumberArray: string[] | number[] = ['hello', 'world'];(string | number)[]: 문자열과 숫자가 섞인 배열string[] | number[]: 문자열 배열이거나 숫자 배열
let arr1: (string | number)[] = ['a', 1, 'b', 2]; // 가능
let arr2: string[] | number[] = ['a', 'b']; // 가능
let arr3: string[] | number[] = [1, 2]; // 가능
let arr4: string[] | number[] = ['a', 1]; // Error4. 리터럴 타입과 유니언 타입
리터럴 타입은 특정 값만 허용하는 타입이다.
유니언 타입과 함께 사용하면 정해진 값 중 하나만 선택하도록 제한할 수 있다.
const toggle = (option: 'on' | 'off') => {
console.log(option);
};
toggle('on');
toggle('off');
toggle(true); // Error
toggle(0); // Error예를 들어 티셔츠 사이즈처럼 정해진 값만 허용해야 하는 경우에 사용할 수 있다.
// 예시: 티셔츠 사이즈 타입
type Size = 'xs' | 's' | 'm' | 'l' | 'xl';
let tShirtSize: Size;
tShirtSize = 'm';
tShirtSize = 'xxl'; // Error
function setSize(size: Size) {
switch (size) {
case 'xs':
console.log('아주 작음');
break;
case 's':
console.log('작음');
break;
case 'm':
console.log('보통');
break;
case 'l':
console.log('큼');
break;
case 'xl':
console.log('아주 큼');
break;
}
}
setSize('m');
setSize('xxl'); // Error5. 타입 별칭 (Type Aliases)
유니언 타입을 자주 쓰는 경우, 타입 별칭을 만들어 재사용할 수 있다.
type SuccessCode = 200 | 201 | 202;
type ErrorCode = 500 | 501 | 503;
let responseCode: SuccessCode | ErrorCode;
responseCode = 200; // 가능
responseCode = 503; // 가능
responseCode = 404; // Error문자열 유니언 타입도 자주 사용된다.
type Status = 'idle' | 'loading' | 'success' | 'error';
let status: Status;
status = 'loading';
status = 'success';
status = 'pending'; // Error6. 객체에 유니언 타입 적용하기
객체 타입에도 유니언 타입을 사용할 수 있다.
type Dog = {
name: string;
color: string;
};
type Person = {
name: string;
language: string;
};
type DogOrPerson = Dog | Person;DogOrPerson 타입은 Dog 타입이거나 Person 타입일 수 있다.
let dog: DogOrPerson = {
name: '돌돌이',
color: 'brown',
};
let person: DogOrPerson = {
name: 'Binny',
language: 'TypeScript',
};Dog의 구조를 만족하거나 Person의 구조를 만족하면 할당할 수 있다.
공통 프로퍼티만 있는 경우
let value: DogOrPerson = {
name: 'unknown',
}; // ErrorDog 타입이 되려면 color가 필요하고, Person 타입이 되려면 language가 필요하다.
하지만 위 객체는 name만 가지고 있으므로 두 타입 중 어느 쪽도 만족하지 못한다.
두 타입의 프로퍼티를 모두 가진 경우
let value: DogOrPerson = {
name: '초코',
color: 'brown',
language: 'Korean',
};위 객체는 Dog 타입이 요구하는 name, color를 가지고 있고,Person 타입이 요구하는 name, language도 가지고 있다.
따라서 Dog | Person 타입에 할당할 수 있다.
6-1. 객체 유니언 타입 사용 시 주의점
객체 유니언 타입의 값을 사용할 때는 공통 프로퍼티에만 바로 접근할 수 있다.
function printInfo(value: Dog | Person) {
console.log(value.name); // 가능
console.log(value.color); // Error
console.log(value.language); // Error
}name은 Dog와 Person에 모두 존재하는 공통 프로퍼티이므로 바로 접근할 수 있다.
하지만 color는 Dog에만 있고, language는 Person에만 있기 때문에 바로 접근할 수 없다.
이럴 때는 타입 좁히기를 사용한다.
function printInfo(value: Dog | Person) {
console.log(value.name);
if ('color' in value) {
console.log(value.color);
}
if ('language' in value) {
console.log(value.language);
}
}in 연산자를 사용하면 특정 프로퍼티가 있는지 확인하면서 타입을 좁힐 수 있다.
👩🏻💻 요약
- 유니언 타입은 여러 타입 중 하나를 허용하는 타입이다.
|기호를 사용해 타입을 연결한다.- 유니언 타입은 함수 매개변수, 배열, 리터럴 타입, 객체 타입 등에 사용할 수 있다.
- 유니언 타입의 값을 사용할 때는 타입 좁히기가 필요한 경우가 많다.
- 객체 유니언 타입에서는 공통 프로퍼티만 바로 접근할 수 있다.
- 특정 프로퍼티에 접근하려면
typeof,in같은 방법으로 타입을 좁혀야 한다.