5. 연산자를 이용한 타입 정의
1. 유니언(Union) 타입
- 유니언 타입이란 자바스크립트의
||
(OR 연산자)와 같은 의미의 타입이다.
function logText(text: string | number) {
// ...
}
- 위 함수의 파라미터
text
에는 문자열 타입이나 숫자 타입 모두 올 수 있다.
- 이처럼
|
연산자를 이용하여 타입을 여러 개 연결하는 방식을 유니언 타입 정의 방식이라고 부른다.
2. 유니언 타입의 장점
- 유니언 타입의 장점은 다음 코드를 비교하면 바로 알 수 있다.
// any를 사용하는 경우
function getAge(age: any) {
// error. age의 타입이 `any`로 추론되기 때문에 숫자 관련된 API를 작성할 때 코드가 자동 완성되지 않는다.
age.toFixe();
return age;
}
// 유니언 타입을 사용하는 경우
function getAge(age: number | string) {
if (typeof age === "number") {
// 정상 동작. age의 타입이 `number`로 추론되기 때문에 숫자 관련된 API를 쉽게 자동완성 할 수 있다.
age.toFixed();
return age;
}
if (typeof age === "string") {
return age;
}
return new TypeError("age must be number or string");
}
- 이처럼
any
를 사용하는 경우 마치 자바스크립트로 작성하는 것처럼 동작을 하고 유니언 타입을 사용하면 타입스크립트의 이점을 살리면서 코딩할 수 있다.
3. 인터섹션(Intersection) 타입
- 인터섹션 타입은 여러 타입을 모두 만족하는 하나의 타입을 의미한다.
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;
}
- 이처럼
&
연산자를 이용해 여러 개의 타입 정의를 하나로 합치는 방식을 인터섹션 타입 정의 방식이라고 한다.
4. 유니언 타입을 쓸 때 주의할 점
- 앞에서 유니언 타입과 인터섹션 타입을 살펴봤다.
- 인터페이스와 같은 타입을 다룰 때는 다음과 같은 논리적 사고를 주의해야 한다.
interface Person {
name: string;
age: number;
}
interface Developer {
name: string;
skill: number;
}
function introduce(someone: Person | Developer) {
someone.name; // 정상 동작
someone.age; // 타입 오류
someone.skill; // 타입 오류
}
- 여기서
introduce()
함수의 파라미터 타입을 Person
, Developer
인터페이스의 유니언 타입으로 정의하였다.
- 유니언 타입은 A도 될 수 있고 B도 될 수 있는 타입이라고 생각하면, 파라미터 타입이
Person
도 되고 Developer
도 되기 때문에 함수 안에서 당연히 이 인터페이스들이 제공하는 속성들인 age
나 skill
을 사용할 수 있다고 생각할 수 있다.
- 하지만, 타입스크립트 관점에서는
introduce()
함수를 호출하는 시점에 Person
타입이 올지 Developer
타입이 올지 알 수 가 없기 때문에 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론하게 된다.
const capt: Person = { name: "capt", age: 100 };
// 만약 `introduce` 함수 안에서 `someone.skill` 속성을 접근하고 있으면 함수에서 오류 발생
introduce(capt);
const tony: Developer = { name: "tony", skill: "iron making" };
// 만약 `introduce` 함수 안에서 `someone.age` 속성을 접근하고 있으면 함수에서 오류 발생
introduce(tony);
- 결과적으로
introduce()
함수 안에서는 별도의 타입 가드(Type Guard)를 이용하여 타입의 범위를 좁히지 않는 이상 기본적으로는 Person
과 Developer
두 타입에 공통적으로 들어있는 속성인 name
만 접근할 수 있게 된다.
function introduce(someone: Person | Developer) {
console.log(someone.name); // O 정상 동작
}
References