대수 타입
1.대수 타입(Algebraic Types)이란?
대수 타입이란 여러 타입을 조합하여 새로운 타입을 만들 수 있는 기능을 말한다.
종류로는 유니온 타입(Union Types),인터섹션 타입(Intersection Types)이 있다.
타입을 집합으로 생각할 때, 집합 간의 연산을 표현하는 방식으로 이해할 수 있다.
유니온 타입은 합집합에 해당하고 인터섹션 타입은 교집합에 해당한다.
1️⃣인터섹션 타입-교집합
인터섹션 타입은 &을 이용해서 교집합 타입을 만든다. 이러한 교집합 타입은 객체타입에서 많이 사용된다.
일반 원시값으로 사용하면 서로 교집합 하는 부분이 없기 때문에 never를 반환하게 된다.
👉🏻원시 타입
let variable : number & string
👉🏻객체 타입
Type Dog = {
name:string;
howling:boolean;
}
Type Cat = {
name:string;
grooming:boolean;
}
type Intersection = Dog & Cat
let intersection:Intersection = {
name:'개냥이',
howling:true,
grooming:true,
}
교집합인 name,howling,grooming의 속성을 만족하는 값만 들어올 수 있게 된다.
2️⃣유니온 타입-합집합
여러 개의 타입을 하나의 타입으로 결합하는 방법이다.
기호(|)를 사용하여 타입들을 나열해 표현한다.
👉🏻기본 타입
let a : string | number;
a = 1; //ok!
a = "hello"; //ok!
string과 number 모두를 포함하기 때문에 둘 다 사용가능.
👉🏻객체 타입
type Dog = {
name:string;
howling:boolean
}
type Cat = {
name:string;
grooming:boolean;
}
type Mixed = Dog | Cat
const cat:Mixed = {
name:"고양이",
grooming:true,
}
const dog:Mixed = {
name:"강아지",
howling:true,
}
const dogCat:Mixed = {
name:"개냥이",
howling:true,
grooming:true
}
이렇게 {name,howling}, {name,grooming} , {name,howling,grooming}
교집합 까지 포함한 세 가지의 형식을 사용할 수 있는 것이다.
2.서로소 유니온 타입(disjoint union type)
서로 중복되지 않는 타입들의 합집합을 표현하는 방법이다. 각각의 타입은 서로 독립적이며,
공통된 속성이 없는 타입들을 조합하여 새로운 타입을 만들 수 있다.
이런 서로소 유니온 타입에서는 구별된 유니온(Discriminated Union)이라는 것을 사용할 수 있다.
이것은 공통된 속성을 사용하여 각각의 타입을 식별할 수 있도록 하여 가독성와 유지보수성을 향상시킨다.
type Dog = {
name: string;
howling: boolean;
};
type Cat = {
name: string;
grooming: boolean;
};
type Bird = {
name: string;
wing: boolean;
};
type Pet = Dog | Cat | Bird;
이러한 서로소 유니온 타입이 있다.
function animal(pet: Pet) {
if ("howling" in pet) {
console.log(`${pet.name}는 하울링을 합니다.`);
} else if ("grooming" in pet) {
console.log(`${pet.name}는 그루밍을 합니다.`);
} else if ("wing" in pet) {
console.log(`${pet.name}는 날개가 있습니다.`);
}
}
매개 변수로 들어오는 pet에 따라 출력이 변경되도록 하기 위해 타입가드를 사용하여 타입을 좁혀줄 수 있다.
이렇게 동작하는것에는 문제는 없지만 구별된 유니온을 사용하여 가독성을 높일 수 있다.
type Dog = {
type: "강아지";
...
};
type Cat = {
type: "고양이";
...
};
type Bird = {
type: "새";
...
};
이렇게 공통의 속성인 type을 추가하고 이를 문자열 리터럴로 정의해준다.
이것을 이용해서 다시 타입가드의 가독성을 높일 수 있다.
function animal(pet: Pet) {
if (pet.type === "강아지") {
console.log(`${pet.name}는 하울링을 합니다.`);
} else if (pet.type === "고양이") {
console.log(`${pet.name}는 그루밍을 합니다.`);
} else if (pet.type === "새") {
console.log(`${pet.name}는 날개가 있습니다.`);
}
}
또는 switch문을 사용해서 만들 수 있다.
function animal(pet: Pet) {
switch(pet.type){
case "강아지":{
console.log(`${pet.name}는 하울링을 합니다.`);
break;
}
case "고양이":{
console.log(`${pet.name}는 그루밍을 합니다.`);
break;
}
case "새":{
console.log(`${pet.name}는 날개가 있습니다.`);
break;
}
}
}
이렇게 구분이 가능한것은 속성에 스트링 리터럴을 사용했기 때문이다.
교집합이 생기기 위해서는 똑같은 스트링 리터럴을 가져야 하는데 그것은 불가능 하기 때문에
집합의 관계들이 완전한 서로소 집합이 되어버린다.