교집합이 없는 타입들로만 만든 유니온 타입
타입 좁히기 할 때 더 직관적으로 쉽고 정확하게 객체 타입을 정의하는 특별한 방법
type Admin = {
name: string;
kickCount: number;
};
type Member = {
name: string;
point: number;
};
type Guest = {
name: string;
visitCount: number;
};
type User = Admin | Member | Guest;
//Admin -> {name} 님 현재까지 {kickCount}명 강퇴했습니다.
//Member -> {name}님 현재까지 {point} 모았습니다.
//Guest -> {name}님 현재까지 {visitCount} 번 오셨습니다.
function logic(user: User) {
if ("kickCount" in user) {
console.log(`${user.name}님 현재까지 ${user.kickCount}명 강퇴했습니다.`);
} else if ("point" in user) {
console.log(`${user.name}님 현재까지 ${user.point} 모았습니다.`);
} else {
console.log(`${user.name}님 현재까지 ${user.visitCount}번 오셨습니다.`);
}
}
바로 각 타입마다 tag를 달아주는 것이다.
태그의 문자열 리터럴타입은 말그대로 한 개만 지정하기 때문에, 겹칠수가 없는것! 그렇기에 admin과 member, member와 guest, admin과 guest는 겹칠 수가 없다. 이렇게 서로소 유니온 타입이 된 것이다.
/**
* 서로소 유니온 타입
* 교집합이 없는 타입들로만 만든 유니온 타입
*/
type Admin = {
tag: 'ADMIN'
name: string;
kickCount: number;
};
type Member = {
tag: 'MEMBER'
name: string;
point: number;
};
type Guest = {
tag: "GUEST"
name: string;
visitCount: number;
};
type User = Admin | Member | Guest;
//Admin -> {name} 님 현재까지 {kickCount}명 강퇴했습니다.
//Member -> {name}님 현재까지 {point} 모았습니다.
//Guest -> {name}님 현재까지 {visitCount} 번 오셨습니다.
function logic(user: User) {
if (user.tag === 'ADMIN') {
console.log(`${user.name}님 현재까지 ${user.kickCount}명 강퇴했습니다.`);
} else if (user.tag === 'MEMBER') {
console.log(`${user.name}님 현재까지 ${user.point} 모았습니다.`);
} else {
console.log(`${user.name}님 현재까지 ${user.visitCount}번 오셨습니다.`);
}
}
function logic(user: User) {
switch (user.tag) {
case "ADMIN": {
console.log(`${user.name}님 현재까지 ${user.kickCount}명 강퇴했습니다.`);
break;
}
case "MEMBER": {
console.log(`${user.name}님 현재까지 ${user.point} 모았습니다.`);
break;
}
case "GUEST": {
console.log(`${user.name}님 현재까지 ${user.visitCount}번 오셨습니다.`);
break;
}
}
}
type AsyncTask = {
state: "LOADING" | "FAILED" | "SUCCESS";
error?: {
message: string;
};
response?: {
data: string;
};
};
?
를 넣어주어 있어도 되고 없어도 되고를 표현했다.function processResult(task: AsyncTask) {
switch (task.state) {
case "LOADING": {
console.log("로딩중");
break;
}
case "FAILED": {
console.log(`에러발생: ${task.error?.message}`);
break;
}
case "SUCCESS": {
console.log(`성공: ${task.response?.data}`);
break;
}
}
}
task.error?.message
task.response?.data
case "FAILED": {
console.log(`에러발생: ${task.error.message}`);
//'task.error'은(는) 'undefined'일 수 있습니다.ts(18048)
break;
}
case "SUCCESS": {
console.log(`성공: ${task.response.data}`);
//'task.response'은(는) 'undefined'일 수 있습니다.ts(18048)
break;
}
type LoadingTask = {
state: "LOADING";
};
type FailedTask = {
state: "FAILED";
error: {
message: string;
};
};
type SuccessTask = {
state: "SUCCESS";
response: {
data: string;
};
};
type AsyncTask = LoadingTask | FailedTask | SuccessTask;
function processResult(task: AsyncTask) {
switch (task.state) {
case "LOADING": {
console.log("로딩중");
break;
}
case "FAILED": {
console.log(`에러발생: ${task.error.message}`);
break;
}
case "SUCCESS": {
console.log(`성공: ${task.response.data}`);
break;
}
}
}
LOADING
, FAILED
, SUCCESS
로 나누어져 있으니 서로 겹칠 수가 없다. FAILED
라면 무조건 FailedTask
인것. 그래서 타입이 잘 좁혀지게 된다.