๐ญ Union Types: ์ฌ๋ฌ ํ์ ์ค ํ๋๋ก ์ ์ํ๊ธฐ ๐ญ

์๋ , ์น๊ตฌ๋ค! ์ค๋์ TypeScript์ ๊ฟ์ผ ๊ธฐ๋ฅ ์ค ํ๋์ธ Union Types์ ๋ํด ์์๋ณผ ๊ฑฐ์ผ. ๐ฏ Union Types๋ผ๊ณ ํ๋ฉด ๋ญ๊ฐ ๋ ธ๋์กฐํฉ ๊ฐ์ ๋๋์ด ๋ค์ง ์์? ํ์ง๋ง ์ฌ๊ธฐ์ ๋งํ๋ Union์ ๊ทธ๋ฐ ๊ฒ ์๋๋ผ, ์ฌ๋ฌ ํ์ ์ ํ๋๋ก '๊ฒฐํฉ'ํ๋ค๋ ์๋ฏธ์ผ. ๋ง์น ์ฌ๋ฌ ๊ฐ์ง ์ฌ๋ฅ์ ๊ฐ์ง ์ฌ๋๋ค์ด ๋ชจ์ฌ ์๋ ์ฌ๋ฅ๋ท์ฒ๋ผ ๋ง์ด์ง! ๐
๐จ Union Types๋? ์ฌ๋ฌ ํ์ ์ค ํ๋๊ฐ ๋ ์ ์๋ ๊ฐ์ ๋ํ๋ด๋ ๋ฐฉ๋ฒ์ด์ผ. ์ฝ๊ฒ ๋งํด, "์ด ๋ณ์๋ ๋ฌธ์์ด์ผ ์๋ ์๊ณ , ์ซ์์ผ ์๋ ์์ด!"๋ผ๊ณ ๋งํ๋ ๊ฑฐ์ง.
์, ์ด์ ๋ถํฐ Union Types์ ์ธ๊ณ๋ก ๋น ์ ธ๋ณผ๊น? ์ค๋น๋์ด? ๊ทธ๋ผ ์ถ๋ฐ! ๐
๐ Union Types์ ๊ธฐ๋ณธ
Union Types๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณ์๋ ํจ์ ๋งค๊ฐ๋ณ์๊ฐ ์ฌ๋ฌ ํ์ ์ค ํ๋์ผ ์ ์๋ค๊ณ ์ ์ธํ ์ ์์ด. ์ด๊ฑธ ์ด๋ป๊ฒ ์ฐ๋๊ณ ? ๊ฐ๋จํด! ํ์ดํ(|) ๊ธฐํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ผ.
let myVariable: string | number;
์ด๋ ๊ฒ ํ๋ฉด myVariable์ ๋ฌธ์์ด์ด๋ ์ซ์ ์ค ํ๋๊ฐ ๋ ์ ์์ด. coolํ์ง? ๐
์๋ฅผ ๋ค์ด๋ณผ๊น? ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์์ ID๋ฅผ ๋ํ๋ด๋ ๋ณ์๋ฅผ ๋ง๋ ๋ค๊ณ ์๊ฐํด๋ณด์. ์ฌ์ฉ์ ID๋ ๋ฌธ์์ด์ผ ์๋ ์๊ณ , ์ซ์์ผ ์๋ ์์ด.
let userId: string | number;
userId = 123; // OK
userId = "abc123"; // ์ด๊ฒ๋ OK
userId = true; // ์๋ฌ! boolean์ ์ ๋ผ์.
์ด๋ ๊ฒ ํ๋ฉด userId๋ ๋ฌธ์์ด์ด๋ ์ซ์๋ง ๋ฐ์ ์ ์๊ณ , ๋ค๋ฅธ ํ์ ์ ํ ๋นํ๋ ค๊ณ ํ๋ฉด TypeScript๊ฐ "์ผ, ๊ทธ๊ฑด ์ ๋ผ!"๋ผ๊ณ ๋งํด์ค ๊ฑฐ์ผ.
๐จ ์ฃผ์์ฌํญ: Union Types๋ฅผ ์ฌ์ฉํ ๋๋ ํด๋น ํ์ ๋ค์ ๊ณตํต ๋ฉ์๋๋ ์์ฑ๋ง ์ฌ์ฉํ ์ ์์ด. ์๋ฅผ ๋ค์ด, string | number ํ์ ์ ๋ณ์์์๋ toString() ๋ฉ์๋๋ ์ฌ์ฉํ ์ ์์ง๋ง, toUpperCase() ๊ฐ์ ๋ฌธ์์ด ์ ์ฉ ๋ฉ์๋๋ ์ฌ์ฉํ ์ ์์ด.
์ด์ ๊ธฐ๋ณธ์ ์์์ผ๋, ์ข ๋ ๊น์ด ๋ค์ด๊ฐ๋ณผ๊น? ๐โโ๏ธ
๐ญ Union Types์ ํจ์
Union Types๋ ํจ์์ ๋งค๊ฐ๋ณ์๋ ๋ฐํ ๊ฐ์๋ ์ฌ์ฉํ ์ ์์ด. ์ด๋ ๊ฒ ํ๋ฉด ํจ์๊ฐ ์ฌ๋ฌ ํ์ ์ ์ ๋ ฅ์ ๋ฐ๊ฑฐ๋, ์ฌ๋ฌ ํ์ ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ง.
์๋ฅผ ๋ค์ด, ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์์ ํ๋กํ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์๋ฅผ ๋ง๋ ๋ค๊ณ ์๊ฐํด๋ณด์. ์ฌ์ฉ์ ID๋ก ๋ฌธ์์ด์ด๋ ์ซ์๋ฅผ ๋ฐ์ ์ ์๊ฒ ํ๊ณ ์ถ์ด.
function getUserProfile(userId: string | number): object {
// ์ฌ์ฉ์ ํ๋กํ์ ๊ฐ์ ธ์ค๋ ๋ก์ง
return {
id: userId,
name: "ํ๊ธธ๋",
skills: ["ํ๋ก๊ทธ๋๋ฐ", "๋์์ธ", "๋ง์ผํ
"]
};
}
console.log(getUserProfile(123)); // OK
console.log(getUserProfile("user456")); // ์ด๊ฒ๋ OK
์ด ํจ์๋ ๋ฌธ์์ด์ด๋ ์ซ์ ํํ์ userId๋ฅผ ๋ฐ์์ ์ฌ์ฉ์ ํ๋กํ ๊ฐ์ฒด๋ฅผ ๋ฐํํด. ์ด๋ค ํํ์ ID๋ฅผ ์ฌ์ฉํ๋ ํจ์๊ฐ ์ ์๋ํ๋ค๋ ๊ฑฐ์ง. ๐
๐ก ํ: ํจ์ ๋ด์์ Union Type์ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ ๋๋ ํ์ ๊ฐ๋(Type Guard)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ์์ ํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ด. ํ์ ๊ฐ๋์ ๋ํด์๋ ๋์ค์ ๋ ์์ธํ ์์๋ณผ ๊ฑฐ์ผ!
์, ์ด์ Union Types๊ฐ ํจ์์์ ์ด๋ป๊ฒ ์ฌ์ฉ๋๋์ง ์์์ง? ๊ทผ๋ฐ ์ฌ๊ธฐ์ ๋์ด ์๋์ผ. Union Types๋ ๋ ๋ณต์กํ ์ํฉ์์๋ ์ฐ๋ฆฌ๋ฅผ ๊ตฌ์ํด์ค ์ ์์ด! ๐ฆธโโ๏ธ
๐จ ๋ฆฌํฐ๋ด ํ์ ๊ณผ Union Types
Union Types์ ์ง๊ฐ๋ ๋ฆฌํฐ๋ด ํ์ ๊ณผ ํจ๊ป ์ฌ์ฉํ ๋ ๋์ฑ ๋น์ ๋ฐํด. ๋ฆฌํฐ๋ด ํ์ ์ด ๋ญ๋๊ณ ? ๊ฐ๋จํ ๋งํด์ ํน์ ๊ฐ ์์ฒด๋ฅผ ํ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฑฐ์ผ.
์๋ฅผ ๋ค์ด, ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์์ ์ญํ ์ ์ ์ํ๋ค๊ณ ์๊ฐํด๋ณด์. ์ฌ์ฉ์๋ "admin", "user", "guest" ์ค ํ๋์ ์ญํ ๋ง ๊ฐ์ง ์ ์์ด.
type UserRole = "admin" | "user" | "guest";
let myRole: UserRole;
myRole = "admin"; // OK
myRole = "superuser"; // ์๋ฌ! "superuser"๋ UserRole์ ์์ด์.
์ด๋ ๊ฒ ํ๋ฉด myRole ๋ณ์๋ ์ค์ง "admin", "user", "guest" ์ค ํ๋์ ๊ฐ๋ง ๊ฐ์ง ์ ์์ด. ๋ค๋ฅธ ๋ฌธ์์ด์ ํ ๋นํ๋ ค๊ณ ํ๋ฉด TypeScript๊ฐ ์๋ฌ๋ฅผ ๋ฐ์์ํฌ ๊ฑฐ์ผ.
์ด๊ฑธ ํ์ฉํด์ ์ฌ๋ฅ๋ท์ ์ฌ์ฉ์ ๊ด๋ฆฌ ํจ์๋ฅผ ๋ง๋ค์ด๋ณผ๊น?
function manageUser(userId: string | number, action: "ban" | "promote" | "demote"): void {
console.log(`User ${userId} is being ${action}ed`);
// ์ค์ ์ฌ์ฉ์ ๊ด๋ฆฌ ๋ก์ง
}
manageUser("user123", "ban"); // OK
manageUser(456, "promote"); // OK
manageUser("admin789", "delete"); // ์๋ฌ! "delete"๋ ํ์ฉ๋ action์ด ์๋์์.
์ด ํจ์๋ ์ฌ์ฉ์ ID(๋ฌธ์์ด ๋๋ ์ซ์)์ ์ํํ ์์ ("ban", "promote", "demote" ์ค ํ๋)์ ๋ฐ์. ๋ง์ฝ ํ์ฉ๋์ง ์์ ์์ ์ ์๋ํ๋ฉด TypeScript๊ฐ ์ปดํ์ผ ๋จ๊ณ์์ ์๋ฌ๋ฅผ ๋ฐ์์์ผ์ค. ์ด๋ ๊ฒ ํ๋ฉด ์ค์๋ก ์๋ชป๋ ์์ ์ ์ํํ๋ ๊ฑธ ๋ฐฉ์งํ ์ ์์ง!
๐ญ ์ฌ๋ฏธ์๋ ์ฌ์ค: ๋ฆฌํฐ๋ด ํ์ ๊ณผ Union Types๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด, ๋ง์น ์ด๊ฑฐํ(enum)์ฒ๋ผ ์ฌ์ฉํ ์ ์์ด. ํ์ง๋ง ๋ ์ ์ฐํ๊ณ , ๋๋ก๋ ๋ ํ์ ์์ ํด!
์, ์ด์ Union Types์ ๋ฆฌํฐ๋ด ํ์ ์ ์กฐํฉ์ด ์ผ๋ง๋ ๊ฐ๋ ฅํ์ง ์๊ฒ ์ง? ์ด๊ฑธ ์ ํ์ฉํ๋ฉด ์ฝ๋์ ์์ ์ฑ์ ํฌ๊ฒ ๋์ผ ์ ์์ด. ๊ทธ๋ผ ์ด์ ์ข ๋ ๋ณต์กํ ์์ ๋ก ๋์ด๊ฐ๋ณผ๊น? ๐
๐งฉ ๊ฐ์ฒด ํ์ ๊ณผ Union Types
Union Types๋ ๋จ์ํ ๊ธฐ๋ณธ ํ์ ๋ฟ๋ง ์๋๋ผ ๋ณต์กํ ๊ฐ์ฒด ํ์ ์๋ ์ ์ฉํ ์ ์์ด. ์ด๊ฑธ ์ด์ฉํ๋ฉด ์ ๋ง ๋ค์ํ ์ํฉ์ ํํํ ์ ์์ง.
์๋ฅผ ๋ค์ด, ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์๊ฐ ๋ฑ๋กํ ์ฌ๋ฅ์ ๋ํ๋ด๋ ํ์ ์ ๋ง๋ค์ด๋ณด์. ์ฌ๋ฅ์ '๊ธฐ์ ์ฌ๋ฅ'๊ณผ '์์ ์ฌ๋ฅ' ๋ ๊ฐ์ง ์ข ๋ฅ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ณผ๊ฒ.
type TechnicalSkill = {
type: "technical";
language: string;
yearsOfExperience: number;
};
type ArtisticSkill = {
type: "artistic";
medium: string;
style: string;
};
type Skill = TechnicalSkill | ArtisticSkill;
function describeSkill(skill: Skill): string {
switch(skill.type) {
case "technical":
return `${skill.language} ๊ฐ๋ฐ์ (${skill.yearsOfExperience}๋
๊ฒฝ๋ ฅ)`;
case "artistic":
return `${skill.medium} ${skill.style} ์ํฐ์คํธ`;
}
}
const coding: Skill = { type: "technical", language: "TypeScript", yearsOfExperience: 3 };
const painting: Skill = { type: "artistic", medium: "์ ํ", style: "์ธ์์ฃผ์" };
console.log(describeSkill(coding)); // "TypeScript ๊ฐ๋ฐ์ (3๋
๊ฒฝ๋ ฅ)"
console.log(describeSkill(painting)); // "์ ํ ์ธ์์ฃผ์ ์ํฐ์คํธ"
์ฌ๊ธฐ์ Skill ํ์ ์ TechnicalSkill๊ณผ ArtisticSkill์ Union Type์ด์ผ. ์ด๋ ๊ฒ ํ๋ฉด ํ๋์ Skill ๋ณ์๊ฐ ๋ ๊ฐ์ง ํ์ ์ ๊ฐ์ฒด ์ค ํ๋๋ฅผ ๊ฐ์ง ์ ์์ง.
๊ทธ๋ฆฌ๊ณ describeSkill ํจ์๋ ์ด Union Type์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์์ ์ ์ ํ ์ค๋ช ์ ๋ฐํํด. ํจ์ ๋ด๋ถ์์๋ skill.type์ ํ์ธํด์ ์ด๋ค ์ข ๋ฅ์ ์ฌ๋ฅ์ธ์ง ๊ตฌ๋ถํ๊ณ , ๊ทธ์ ๋ง๋ ์ค๋ช ์ ๋ง๋ค์ด๋ด์ง.
๐ ์ฃผ๋ชฉํ ์ : ์ด๋ฐ ๋ฐฉ์์ 'ํ๊ทธ๋ ์ ๋์จ(Tagged Union)' ๋๋ 'ํ๋ณ ์ ๋์จ(Discriminated Union)'์ด๋ผ๊ณ ๋ถ๋ฌ. type ์์ฑ์ด ์ด๋ค ์ข ๋ฅ์ ๊ฐ์ฒด์ธ์ง 'ํ๊ทธ'ํ๋ ์ญํ ์ ํ๊ธฐ ๋๋ฌธ์ด์ง.
์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ํ์ ์์ ํ๊ฒ ๋ค๋ฃฐ ์ ์์ด. ์๋ฅผ ๋ค์ด, ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์ ํ๋กํ์ ํํํ ๋ ์ด๋ฐ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์๊ฒ ์ง?
type UserProfile = {
id: string | number;
name: string;
skills: Skill[];
};
const myProfile: UserProfile = {
id: "user123",
name: "๊น์ฌ๋ฅ",
skills: [
{ type: "technical", language: "JavaScript", yearsOfExperience: 5 },
{ type: "artistic", medium: "๋์งํธ ์ํธ", style: "๋ฏธ๋๋ฉ๋ฆฌ์ฆ" }
]
};
myProfile.skills.forEach(skill => console.log(describeSkill(skill)));
์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์์ ๋ค์ํ ์ฌ๋ฅ์ ํ์ ์์ ํ๊ฒ ํํํ๊ณ ๋ค๋ฃฐ ์ ์์ด. ๋ฉ์ง์ง ์์? ๐
์, ์ด์ Union Types๊ฐ ์ผ๋ง๋ ๊ฐ๋ ฅํ์ง ์๊ฒ ์ง? ํ์ง๋ง ์์ง ๋ ์์ด! Union Types๋ฅผ ์ ๋๋ก ํ์ฉํ๋ ค๋ฉด 'ํ์ ๊ฐ๋'๋ผ๋ ๊ฐ๋ ๋ ์์์ผ ํด. ๋ค์ ์น์ ์์ ์์ธํ ์์๋ณด์! ๐
๐ก๏ธ ํ์ ๊ฐ๋์ Union Types
ํ์ ๊ฐ๋(Type Guard)๋ Union Type์ ๋ณ์๋ฅผ ์ฌ์ฉํ ๋ ํน์ ํ์ ์์ ๋ณด์ฅํ๋ ๋ฐฉ๋ฒ์ด์ผ. ์ด๊ฑธ ์ฌ์ฉํ๋ฉด Union Type์ ๋ณ์๋ฅผ ๋ ์์ ํ๊ณ ํจ๊ณผ์ ์ผ๋ก ๋ค๋ฃฐ ์ ์์ง.
ํ์ ๊ฐ๋์๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ด. ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๊ฒ๋ถํฐ ์ดํด๋ณผ๊น?
1. typeof ์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id.toFixed(2));
}
}
printId("user123"); // USER123
printId(123.456); // 123.46
์ด ์์ ์์ typeof ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด id๊ฐ ๋ฌธ์์ด์ธ์ง ์ซ์์ธ์ง ํ์ธํ๊ณ ์์ด. TypeScript๋ ์ด ๊ฒ์ฌ๋ฅผ ์ธ์ํ๊ณ , ๊ฐ ๋ธ๋ก ๋ด์์ id๋ฅผ ์ ์ ํ ํ์ ์ผ๋ก ์ฒ๋ฆฌํด.
2. instanceof ์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
๊ฐ์ฒด์ ๊ฒฝ์ฐ instanceof๋ฅผ ์ฌ์ฉํ ์ ์์ด. ์ฌ๋ฅ๋ท์ ์ฌ์ฉ์ ์์คํ ์ ์๋ก ๋ค์ด๋ณผ๊น?
class NormalUser {
constructor(public username: string) {}
sayHello() {
console.log(`์๋
ํ์ธ์, ${this.username}์
๋๋ค!`);
}
}
class AdminUser {
constructor(public username: string, public adminLevel: number) {}
performAdminTask() {
console.log(`${this.username} ๊ด๋ฆฌ์๊ฐ ๊ด๋ฆฌ ์์
์ ์ํํฉ๋๋ค.`);
}
}
function greetUser(user: NormalUser | AdminUser) {
if (user instanceof AdminUser) {
console.log(`๊ด๋ฆฌ์ ${user.username}๋, ํ์ํฉ๋๋ค!`);
user.performAdminTask();
} else {
user.sayHello();
}
}
const normalUser = new NormalUser("๊น์ฌ๋ฅ");
const adminUser = new AdminUser("๋ฐ๊ด๋ฆฌ", 1);
greetUser(normalUser); // ์๋
ํ์ธ์, ๊น์ฌ๋ฅ์
๋๋ค!
greetUser(adminUser); // ๊ด๋ฆฌ์ ๋ฐ๊ด๋ฆฌ๋, ํ์ํฉ๋๋ค! ๋ฐ๊ด๋ฆฌ ๊ด๋ฆฌ์๊ฐ ๊ด๋ฆฌ ์์
์ ์ํํฉ๋๋ค.
์ด ์์ ์์ instanceof๋ฅผ ์ฌ์ฉํด user๊ฐ AdminUser์ ์ธ์คํด์ค์ธ์ง ํ์ธํ๊ณ ์์ด. ์ด๋ฅผ ํตํด ๊ฐ ์ฌ์ฉ์ ํ์ ์ ๋ง๋ ๋์์ ์ํํ ์ ์์ง.
3. in ์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
๊ฐ์ฒด์ ํน์ ํ๋กํผํฐ๊ฐ ์๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ๋ ์์ด. ์ฌ๋ฅ๋ท์ ์ฌ๋ฅ ์์คํ ์ ๋ค์ ์๋ก ๋ค์ด๋ณผ๊ฒ.
type TechnicalSkill = { type: "technical", language: string };
type ArtisticSkill = { type: "artistic", medium: string };
function describeSkill(skill: TechnicalSkill | ArtisticSkill) {
if ("language" in skill) {
console.log(`๊ธฐ์ ์ฌ๋ฅ: ${skill.language}`);
} else {
console.log(`์์ ์ฌ๋ฅ: ${skill.medium}`);
}
}
describeSkill({ type: "technical", language: "TypeScript" }); // ๊ธฐ์ ์ฌ๋ฅ: TypeScript
describeSkill({ type: "artistic", medium: "์์ฑํ" }); // ์์ ์ฌ๋ฅ: ์์ฑํ
์ฌ๊ธฐ์๋ 'in' ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด skill ๊ฐ์ฒด์ 'language' ํ๋กํผํฐ๊ฐ ์๋์ง ํ์ธํ๊ณ ์์ด. ์ด ๋ฐฉ๋ฒ์ ๊ฐ์ฒด์ ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ ์ ๊ตฌ๋ถํ ๋ ์ ์ฉํด.
4. ์ฌ์ฉ์ ์ ์ ํ์ ๊ฐ๋
๋๋ก๋ ๋ ๋ณต์กํ ๋ก์ง์ด ํ์ํ ์ ์์ด. ์ด๋ด ๋๋ ์ฌ์ฉ์ ์ ์ ํ์ ๊ฐ๋๋ฅผ ๋ง๋ค ์ ์์ง.
function isTechnicalSkill(skill: TechnicalSkill | ArtisticSkill): skill is TechnicalSkill {
return (skill as TechnicalSkill).language !== undefined;
}
function enhanceSkill(skill: TechnicalSkill | ArtisticSkill) {
if (isTechnicalSkill(skill)) {
console.log(`${skill.language} ์ค๋ ฅ์ ํฅ์์ํต๋๋ค.`);
} else {
console.log(`${skill.medium} ๊ธฐ๋ฒ์ ์ฐ๋งํฉ๋๋ค.`);
}
}
enhanceSkill({ type: "technical", language: "Python" }); // Python ์ค๋ ฅ์ ํฅ์์ํต๋๋ค.
enhanceSkill({ type: "artistic", medium: "์กฐ๊ฐ" }); // ์กฐ๊ฐ ๊ธฐ๋ฒ์ ์ฐ๋งํฉ๋๋ค.
์ฌ๊ธฐ์ isTechnicalSkill ํจ์๋ ์ฌ์ฉ์ ์ ์ ํ์ ๊ฐ๋์ผ. ์ด ํจ์๋ skill์ด TechnicalSkill ํ์ ์ธ์ง ํ์ธํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ TypeScript์๊ฒ ์๋ ค์ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ ๋ณต์กํ ํ์ ์ฒดํฌ๋ ๊ฐ๋ฅํด์ง์ง.
๐ก ํ: ํ์ ๊ฐ๋๋ฅผ ์ ์ฌ์ฉํ๋ฉด Union Types๋ฅผ ๋์ฑ ์์ ํ๊ณ ํจ๊ณผ์ ์ผ๋ก ๋ค๋ฃฐ ์ ์์ด. ์ฝ๋์ ๊ฐ๋ ์ฑ๋ ์ข์์ง๊ณ , ๋ฒ๊ทธ๋ ์ค์ผ ์ ์์ง!
์, ์ด์ ํ์ ๊ฐ๋์ ๋ํด ์์์ผ๋ Union Types๋ฅผ ๋ ์์ ์๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ์ง? ํ์ง๋ง ์์ง ๋์ด ์๋์ผ. Union Types์ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ด ๋ ๋จ์์์ด! ๋ค์ ์น์ ์์ ๊ณ์ ์์๋ณด์! ๐
๐ Union Types์ ๊ณ ๊ธ ๊ธฐ๋ฅ
์, ์ด์ Union Types์ ๊ธฐ๋ณธ์ ๋ง์คํฐํ์ผ๋ ์ข ๋ ๊ณ ๊ธ ๊ธฐ๋ฅ์ผ๋ก ๋์ด๊ฐ๋ณผ๊น? ์ฌ๊ธฐ์๋ถํฐ๋ ์ง์ง TypeScript์ ๊ฐ๋ ฅํจ์ ๋๋ ์ ์์ ๊ฑฐ์ผ! ๐
1. Discriminated Unions (ํ๋ณ ์ ๋์จ)
์ด๋ฏธ ๊ฐ๋จํ ๋ค๋ค์ง๋ง, ํ๋ณ ์ ๋์จ์ ์ ๋ง ์ ์ฉํด์ ๋ ์์ธํ ์์๋ณผ ๊ฐ์น๊ฐ ์์ด. ์ฌ๋ฅ๋ท์ ๊ฒฐ์ ์์คํ ์ ์๋ก ๋ค์ด๋ณผ๊ฒ.
type Cash = {
kind: "cash";
amount: number;
};
type CreditCard = {
kind: "credit";
cardNumber: string;
securityCode: string;
};
type BankTransfer = {
kind: "transfer";
accountNumber: string;
bankCode: string;
};
type Payment = Cash | CreditCard | BankTransfer;
function processPayment(payment: Payment) {
switch(payment.kind) {
case "cash":
console.log(`${payment.amount}์์ ํ๊ธ์ผ๋ก ๋ฐ์์ต๋๋ค.`);
break;
case "credit":
console.log(`์นด๋ ๋ฒํธ ${payment.cardNumber}๋ก ๊ฒฐ์ ๋ฅผ ์งํํฉ๋๋ค.`);
break;
case "transfer":
console.log(`${payment.bankCode} ์ํ์ ๊ณ์ข ${payment.accountNumber}๋ก ์ด์ฒด๋ฅผ ์งํํฉ๋๋ค.`);
break;
}
}
processPayment({ kind: "cash", amount: 50000 });
processPayment({ kind: "credit", cardNumber: "1234-5678-9012-3456", securityCode: "123" });
processPayment({ kind: "transfer", accountNumber: "987-65-43210", bankCode: "WB" });
์ฌ๊ธฐ์ 'kind' ์์ฑ์ด ํ๋ณ์(discriminator) ์ญํ ์ ํด. TypeScript๋ ์ด๋ฅผ ํตํด ๊ฐ case์์ ์ ํํ ํ์ ์ ์ถ๋ก ํ ์ ์์ง. ์ด๋ ๊ฒ ํ๋ฉด ํ์ ์์ ์ฑ์ ์ ์งํ๋ฉด์๋ ๋ค์ํ ๊ฒฐ์ ๋ฐฉ์์ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์์ด.
2. Exhaustiveness Checking (์์ ์ฑ ๊ฒ์ฌ)
ํ๋ณ ์ ๋์จ์ ์ฌ์ฉํ ๋, ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํ๋์ง ํ์ธํ๋ ๊ฒ์ด ์ค์ํด. TypeScript๋ ์ด๋ฅผ ์ํ ํธ๋ฆญ์ ์ ๊ณตํด.
function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}
function processPayment(payment: Payment) {
switch(payment.kind) {
case "cash":
console.log(`${payment.amount}์์ ํ๊ธ์ผ๋ก ๋ฐ์์ต๋๋ค.`);
break;
case "credit":
console.log(`์นด๋ ๋ฒํธ ${payment.cardNumber}๋ก ๊ฒฐ์ ๋ฅผ ์งํํฉ๋๋ค.`);
break;
case "transfer":
console.log(`${payment.bankCode} ์ํ์ ๊ณ์ข ${payment.accountNumber}๋ก ์ด์ฒด๋ฅผ ์งํํฉ๋๋ค.`);
break;
default:
assertNever(payment); // ์ฌ๊ธฐ์ ๋๋ฌํ๋ฉด ์ปดํ์ผ ์๋ฌ!
}
}
assertNever ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด, ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํ์ง ์์์ ๋ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํด. ์ด๋ ๊ฒ ํ๋ฉด ๋์ค์ Payment ํ์ ์ ์๋ก์ด ๊ฒฐ์ ๋ฐฉ์์ ์ถ๊ฐํ์ ๋, ๋ฐ๋์ ๊ทธ ์ผ์ด์ค๋ฅผ ์ฒ๋ฆฌํ๋๋ก ๊ฐ์ ํ ์ ์์ง.
3. Intersection Types์์ ์กฐํฉ
Union Types๋ Intersection Types์ ํจ๊ป ์ฌ์ฉ๋ ๋ ๋์ฑ ๊ฐ๋ ฅํด์ ธ. ์ฌ๋ฅ๋ท์ ์ฌ์ฉ์ ํ๋กํ ์์คํ ์ ์๋ก ๋ค์ด๋ณผ๊ฒ.
type BasicProfile = {
name: string;
age: number;
};
type SkillProfile = {
skills: string[];
};
type SocialProfile = {
socialLinks: { [key: string]: string };
};
type UserProfile = BasicProfile & (SkillProfile | SocialProfile);
function displayProfile(profile: UserProfile) {
console.log(`์ด๋ฆ: ${profile.name}, ๋์ด: ${profile.age}`);
if ("skills" in profile) {
console.log(`๋ณด์ ๊ธฐ์ : ${profile.skills.join(", ")}`);
} else {
console.log(`์์
๋งํฌ: ${Object.keys(profile.socialLinks).join(", ")}`);
}
}
displayProfile({
name: "๊น์ฌ๋ฅ",
age: 28,
skills: ["TypeScript", "React", "Node.js"]
});
displayProfile({
name: "์ด์์
",
age: 32,
socialLinks: {
twitter: "https://twitter.com/leesocial",
instagram: "https://instagram.com/leesocial"
}
});
์ฌ๊ธฐ์ UserProfile์ BasicProfile๊ณผ (SkillProfile ๋๋ SocialProfile)์ ์กฐํฉ์ด์ผ. ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ ์ฌ์ฉ์๊ฐ ๊ธฐ๋ณธ ์ ๋ณด๋ฅผ ๊ฐ์ง๋ฉด์, ์ถ๊ฐ๋ก ๊ธฐ์ ์ ๋ณด๋ ์์ ์ ๋ณด ์ค ํ๋๋ฅผ ๊ฐ์ง ์ ์๊ฒ ๋ผ. ์ด๋ฐ ๋ฐฉ์์ผ๋ก ๋ณต์กํ ํ์ ๊ตฌ์กฐ๋ฅผ ์ ์ฐํ๊ฒ ํํํ ์ ์์ง.
4. Conditional Types์์ ํ์ฉ
Union Types๋ Conditional Types์ ํจ๊ป ์ฌ์ฉ๋ ๋ ๋์ฑ ๊ฐ๋ ฅํ ํ์ ๋ก์ง์ ๊ตฌํํ ์ ์์ด. ์ฌ๋ฅ๋ท์ ๊ฒ์ ์์คํ ์ ์๋ก ๋ค์ด๋ณผ๊ฒ.
type SearchBy<T> = T extends "skill" ? { skill: string } :
T extends "name" ? { name: string } :
T extends "location" ? { city: string, country: string } :
never;
function search<T extends "skill" | "name" | "location">(searchType: T, query: SearchBy<T>) {
// ๊ฒ์ ๋ก์ง
console.log(`Searching by ${searchType}:`, query);
}
search("skill", { skill: "TypeScript" });
search("name", { name: "๊น์ฌ๋ฅ" });
search("location", { city: "์์ธ", country: "๋ํ๋ฏผ๊ตญ" });
// search("age", { age: 30 }); // ์ปดํ์ผ ์๋ฌ!
์ด ์์ ์์ SearchBy๋ Conditional Type์ ์ฌ์ฉํด ๊ฒ์ ํ์ ์ ๋ฐ๋ผ ์ ์ ํ ์ฟผ๋ฆฌ ๊ฐ์ฒด ํ์ ์ ๋ฐํํด. ์ด๋ ๊ฒ ํ๋ฉด ํ์ ์์ ์ฑ์ ์ ์งํ๋ฉด์๋ ์ ์ฐํ ๊ฒ์ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์ง.
๐ ๊ณ ๊ธ ํ: Union Types, Intersection Types, Conditional Types๋ฅผ ์กฐํฉํ๋ฉด ์ ๋ง ๋ณต์กํ ํ์ ๋ก์ง๋ ํํํ ์ ์์ด. ํ์ง๋ง ๋๋ฌด ๋ณต์กํด์ง๋ฉด ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง ์ ์์ผ๋ ์ ์ ํ ๊ท ํ์ ์ฐพ๋ ๊ฒ ์ค์ํด!
5. Mapped Types์ Union Types
Mapped Types๋ฅผ Union Types์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋์ฑ ๊ฐ๋ ฅํ ํ์ ๋ณํ์ ํ ์ ์์ด. ์ฌ๋ฅ๋ท์ ์ฌ์ฉ์ ์ค์ ์์คํ ์ ์๋ก ๋ค์ด๋ณผ๊ฒ.
type UserPreferences = {
theme: "light" | "dark";
fontSize: "small" | "medium" | "large";
notifications: "all" | "important" | "none";
};
type PreferenceToggle<T> = {
[K in keyof T]: {
enable: boolean;
value: T[K];
}
};
type UserPreferencesToggle = PreferenceToggle<UserPreferences>;
const userSettings: UserPreferencesToggle = {
theme: { enable: true, value: "dark" },
fontSize: { enable: false, value: "medium" },
notifications: { enable: true, value: "important" }
};
function applySettings(settings: UserPreferencesToggle) {
for (const [key, { enable, value }] of Object.entries(settings)) {
if (enable) {
console.log(`Applying ${key}: ${value}`);
} else {
console.log(`Skipping ${key}`);
}
}
}
applySettings(userSettings);
์ด ์์ ์์ PreferenceToggle์ Mapped Type์ ์ฌ์ฉํด ๊ฐ ์ค์ ์ enable ์์ฑ์ ์ถ๊ฐํด. ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ ์ค์ ์ ๊ฐ๋ณ์ ์ผ๋ก ํ์ฑํํ๊ฑฐ๋ ๋นํ์ฑํํ ์ ์์ง.
๋ง๋ฌด๋ฆฌ
์, ์ด์ Union Types์ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค๊น์ง ์ดํด๋ดค์ด. ์ด๋ฐ ๊ธฐ๋ฅ๋ค์ ์ ํ์ฉํ๋ฉด ์ ๋ง ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ํ์ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ง. TypeScript์ ์ง์ ํ ํ์ ์ด๋ฐ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ค์ ์กฐํฉํด์ ์ฌ์ฉํ ๋ ๋ํ๋!
Union Types๋ ๋จ์ํ ์ฌ๋ฌ ํ์ ์ค ํ๋๋ฅผ ์ ํํ๋ ๊ฒ ์ด์์ ์๋ฏธ๋ฅผ ๊ฐ์ ธ. ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง, ๋ค์ํ ์ฌ์ฉ์ ์๋๋ฆฌ์ค, ๊ทธ๋ฆฌ๊ณ ์ ์ฐํ API ์ค๊ณ ๋ฑ ๋ค์ํ ์ํฉ์์ ํ์ฉ๋ ์ ์์ด. ํนํ ์ฌ๋ฅ๋ท ๊ฐ์ ๋ณต์กํ ํ๋ซํผ์ ๊ฐ๋ฐํ ๋ ์ด๋ฐ ๊ธฐ๋ฅ๋ค์ด ํฐ ๋์์ด ๋ ๊ฑฐ์ผ.
๊ณ์ ์ฐ์ตํ๊ณ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณด๋ฉด์ ์ด ๊ฐ๋ ๋ค์ ๋ง์คํฐํด๋๊ฐ๊ธธ ๋ฐ๋ผ! TypeScript์ ์ธ๊ณ๋ ์ ๋ง ๊น๊ณ ๋์ผ๋๊น, ํญ์ ์๋ก์ด ๊ฒ์ ๋ฐฐ์ธ ์ค๋น๋ฅผ ํ๊ณ ์์ด์ผ ํด. ํ์ดํ ! ๐๐
๐ ๋ง๋ฌด๋ฆฌ: Union Types ๋ง์คํฐํ๊ธฐ
์ฐ์, ์ ๋ง ๊ธด ์ฌ์ ์ด์์ง๋ง ๋๋์ด Union Types์ ์ธ๊ณ๋ฅผ ํํํ์ด! ๐ ์ด์ Union Types๊ฐ ์ผ๋ง๋ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ๋๊ตฌ์ธ์ง ์๊ฒ ๋์ ๊ฑฐ์ผ. ์ฌ๋ฅ๋ท ๊ฐ์ ๋ณต์กํ ํ๋ซํผ์ ๊ฐ๋ฐํ ๋ ์ด๋ฐ ์ง์์ ์ ๋ง ํฐ ๋์์ด ๋ ๊ฑฐ์ผ.
์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ๋ด์ฉ์ ๊ฐ๋จํ ์ ๋ฆฌํด๋ณผ๊น?
- Union Types์ ๊ธฐ๋ณธ ๊ฐ๋ ๊ณผ ์ฌ์ฉ๋ฒ
- ํจ์์์ Union Types ํ์ฉํ๊ธฐ
- ๋ฆฌํฐ๋ด ํ์ ๊ณผ Union Types์ ์กฐํฉ
- ๊ฐ์ฒด ํ์ ๊ณผ Union Types
- ํ์ ๊ฐ๋๋ฅผ ์ด์ฉํ ์์ ํ Union Types ์ฌ์ฉ
- Discriminated Unions (ํ๋ณ ์ ๋์จ)
- Exhaustiveness Checking (์์ ์ฑ ๊ฒ์ฌ)
- Intersection Types์์ ์กฐํฉ
- Conditional Types์ Union Types
- Mapped Types์ Union Types
์ด ๋ชจ๋ ๊ฐ๋ ๋ค์ ์์ ํ ์ดํดํ๊ณ ํ์ฉํ๋ ๋ฐ๋ ์๊ฐ์ด ๊ฑธ๋ฆด ๊ฑฐ์ผ. ํ์ง๋ง ๊ฑฑ์ ํ์ง ๋ง! ํ๋ก๊ทธ๋๋ฐ์ ๊ณ์ ์ฐ์ตํ๊ณ ๊ฒฝํ์ ์์๊ฐ๋ ๊ณผ์ ์ด๋๊น. ๐
๐ก ์์ผ๋ก์ ํ์ต ํ:
- ์ค์ ํ๋ก์ ํธ์ Union Types๋ฅผ ์ ์ฉํด๋ณด์ธ์.
- ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ ์ฝ๋๋ฅผ ์ฝ๊ณ Union Types๊ฐ ์ด๋ป๊ฒ ์ฌ์ฉ๋๋์ง ๊ด์ฐฐํ์ธ์.
- ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ Union Types๋ก ๋ชจ๋ธ๋งํด๋ณด๋ ์ฐ์ต์ ํ์ธ์.
- TypeScript์ ๊ณต์ ๋ฌธ์๋ฅผ ์์ฃผ ์ฐธ๊ณ ํ์ธ์. ํญ์ ์๋ก์ด ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋๊ณ ์์ด์!
Union Types๋ TypeScript์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋์ผ. ์ด๋ฅผ ๋ง์คํฐํ๋ฉด ๋ ์์ ํ๊ณ , ๋ ์ ์ฐํ๋ฉฐ, ๋ ํํ๋ ฅ ์๋ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ ๊ฑฐ์ผ. ์ฌ๋ฅ๋ท ๊ฐ์ ๋ณต์กํ ์์คํ ์ ๊ฐ๋ฐํ ๋, ์ด๋ฐ ํ์ ์์คํ ์ ํ์ ์ ๋๋ก ํ์ฉํ๋ฉด ์ ๋ง ํฐ ์ฐจ์ด๋ฅผ ๋ง๋ค ์ ์์ง.
์, ์ด์ ๋น์ ์ Union Types์ ์ง์ ํ ๋ง์คํฐ๋ก ๊ฑฐ๋ญ๋ฌ์ด! ๐ ์ด ์ง์์ ๊ฐ์ง๊ณ ๋ ๋ฉ์ง ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋๊ฐ๊ธธ ๋ฐ๋ผ. ํญ์ ์๋ก์ด ๊ฒ์ ๋ฐฐ์ฐ๊ณ , ๋์ ํ๋ ์์ธ๋ฅผ ์์ง ๋ง์ธ์. TypeScript์ ์ธ๊ณ๋ ์์ง ๋ ๋ง์ ํฅ๋ฏธ๋ก์ด ๊ธฐ๋ฅ๋ค๋ก ๊ฐ๋ํ๋๊น์!
๋ค์์ ๋ ๋ค๋ฅธ ํฅ๋ฏธ๋ก์ด TypeScript ์ฃผ์ ๋ก ๋ง๋๊ธธ ๋ฐ๋ผ์. ์ฝ๋ฉ ์ฌ๋ฅ ๊ฐ๋ํ ์ฌ๋ฌ๋ถ, ๋ชจ๋ ํ์ดํ ! ๐๐ปโจ
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ