구별된 유니온이란, 유니온 타입을 구성하는 타입들의 공통된 "리터럴 타입" 필드를 통해서 구분하는것을 의미한다.
아래와 같이 두개의 인터페이스가 있다고 가정하자.
interface Bird {
flyingSpeed: number;
}
interface Horse {
runningSpeed: number;
}
type Animal = Bird | Horse;
그리고 Animal
타입 변수를 받아 동물의 속도를 출력하는 함수를 구현한다고 가정한다.
function getAnimalSpped(animal: Animal) {
console.log(animal.flyingSpeed); // 'Animal' 형식에 'flyingSpeed' 속성이 없습니다.'Horse' 형식에 'flyingSpeed' 속성이 없습니다.
console.log(animal.runningSpeed); // 'Animal' 형식에 'runningSpeed' 속성이 없습니다.'Bird' 형식에 'runningSpeed' 속성이 없습니다.
}
당연하게도 오류가 난다. Bird
인터페이스에는 runningSpeed
가 없으며 Horse
에는 flyingSpeed
가 존재하지 않기 때문이다. 물론 in
을 활용한 TypeGuard를 해줄 수 있지만, 문자열을 하드코딩 해야하므로 발생할 수 있는 위험성은 여전하다.
각각의 Bird
와 Horse
에 type
이라는 속성을 만들고, 리터럴 타입으로 각각 bird
,horse
로 작성해준다.
interface Bird {
type: "bird";
flyingSpeed: number;
}
interface Horse {
type: "horse";
runningSpeed: number;
}
이렇게 하게 되면, TypeScript는 공통된 리터럴 타입을 인식하고, 사용자에게 각각의 객체를 리터럴타입을 통해 구분하도록 자동완성을 제공한다. 공통된 type
필드의 리터럴 타입을 통해 Animal
타입 객체들간의 TypeGuard를 해줄 수 있다. 그리고 이것이 구별된 유니온의 핵심적 특징이다.
getAnimalSpeed
함수를 switch - case를 통해 아래와 같이 작성해줄 수 있다.
function getAnimalSpped(animal: Animal) {
let speed: number = 0;
switch (animal.type) {
case "bird":
speed = animal.flyingSpeed;
break;
case "horse":
speed = animal.runningSpeed;
break;
}
console.log(`${animal.type} is moving with speed ${speed}km`);
}
getAnimalSpped({
type: "bird",
flyingSpeed: 10,
});