================================================================================ TYPESCRIPT FUNDAMENTALS - CHALLENGE 1 SOLUTION Chapter 9: Enums & Literal Types Challenge: String Enum ================================================================================ PROBLEM: Create a Color enum with at least 5 colors (Red, Green, Blue, Yellow, Purple). Write a function that accepts a color and returns a CSS color code. SOLUTION: ================================================================================ // Define the Color enum with string values enum Color { Red = "#FF0000", Green = "#00FF00", Blue = "#0000FF", Yellow = "#FFFF00", Purple = "#800080" } // Function that maps enum to CSS color code function getCSSColor(color: Color): string { return color; } // Alternative: function that returns color name + code function getColorInfo(color: Color): { name: string; code: string } { const colorMap: Record = { [Color.Red]: "Red", [Color.Green]: "Green", [Color.Blue]: "Blue", [Color.Yellow]: "Yellow", [Color.Purple]: "Purple" }; return { name: colorMap[color], code: color }; } // Testing the solution console.log("=== Color Enum Test ===\n"); console.log(getCSSColor(Color.Red)); // "#FF0000" console.log(getCSSColor(Color.Green)); // "#00FF00" console.log(getCSSColor(Color.Blue)); // "#0000FF" console.log(getCSSColor(Color.Yellow)); // "#FFFF00" console.log(getCSSColor(Color.Purple)); // "#800080" console.log("\n=== Color Info Test ===\n"); console.log(getColorInfo(Color.Red)); // { name: "Red", code: "#FF0000" } console.log(getColorInfo(Color.Blue)); // { name: "Blue", code: "#0000FF" } // Type-safe: TypeScript won't allow arbitrary strings // getCSSColor("red"); // ❌ Error! Must be Color enum value ================================================================================ WHY THIS WORKS: ================================================================================ 1. String Enum Definition enum Color { Red = "#FF0000", Green = "#00FF00", ... } - Each enum member has an explicit string value - The enum member name (Red) maps to the value (#FF0000) 2. Type Safety - When you call getCSSColor(Color.Red), TypeScript knows it's valid - You cannot pass arbitrary strings: getCSSColor("red") is an error - This prevents runtime bugs from typos 3. Reverse Mapping with Record - Record creates a type-safe mapping - [Color.Red]: "Red" uses computed property syntax - This ensures you handle all color cases 4. Function Overloading Alternative You could also create specific functions: - getCSSColorCode(color: Color): string - getColorName(color: Color): string But one function returning an object is often cleaner. ================================================================================ ALTERNATIVE APPROACHES: ================================================================================ Approach 1: Using Literal Union Instead (Modern) type Color = "red" | "green" | "blue" | "yellow" | "purple"; const colorMap: Record = { red: "#FF0000", green: "#00FF00", blue: "#0000FF", yellow: "#FFFF00", purple: "#800080" }; function getCSSColor(color: Color): string { return colorMap[color]; } // Simpler, no enum needed! Approach 2: Using Object as Enum (Very Modern) const Color = { Red: "#FF0000", Green: "#00FF00", Blue: "#0000FF", Yellow: "#FFFF00", Purple: "#800080" } as const; type Color = typeof Color[keyof typeof Color]; function getCSSColor(color: Color): string { return color; } // Most flexible approach Approach 3: Numeric Enum (Less Common) enum Color { Red = 0, Green = 1, Blue = 2, Yellow = 3, Purple = 4 } const colorCodes: Record = { [Color.Red]: "#FF0000", [Color.Green]: "#00FF00", [Color.Blue]: "#0000FF", [Color.Yellow]: "#FFFF00", [Color.Purple]: "#800080" }; // Numeric enums have reverse mapping built-in console.log(Color[0]); // "Red" ================================================================================ REAL-WORLD EXAMPLES: ================================================================================ Example 1: Status Enum enum OrderStatus { Pending = "pending", Processing = "processing", Shipped = "shipped", Delivered = "delivered", Cancelled = "cancelled" } function getStatusColor(status: OrderStatus): string { switch (status) { case OrderStatus.Pending: return "#FFA500"; // Orange case OrderStatus.Processing: return "#0000FF"; // Blue case OrderStatus.Shipped: return "#4169E1"; // Purple case OrderStatus.Delivered: return "#00FF00"; // Green case OrderStatus.Cancelled: return "#FF0000"; // Red } } Example 2: User Role Enum enum UserRole { Admin = "admin", Moderator = "moderator", User = "user", Guest = "guest" } function canEdit(role: UserRole): boolean { return role === UserRole.Admin || role === UserRole.Moderator; } function getPermissionLevel(role: UserRole): number { switch (role) { case UserRole.Admin: return 100; case UserRole.Moderator: return 50; case UserRole.User: return 10; case UserRole.Guest: return 0; } } Example 3: Priority Enum enum Priority { Low = "low", Medium = "medium", High = "high", Urgent = "urgent" } const priorityLabels: Record = { [Priority.Low]: "Low Priority", [Priority.Medium]: "Medium Priority", [Priority.High]: "High Priority", [Priority.Urgent]: "URGENT - Handle immediately" }; function displayPriority(priority: Priority) { console.log(priorityLabels[priority]); } ================================================================================ TESTING & VERIFICATION: ================================================================================ // Comprehensive tests console.log("=== Comprehensive Testing ===\n"); // Test 1: All colors compile and return correct values const allColors = [Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Purple]; console.log("Test 1 - All colors:"); allColors.forEach(color => { const code = getCSSColor(color); console.log(` ${color} = ${code}`); }); // Test 2: Color info retrieval console.log("\nTest 2 - Color info:"); const redInfo = getColorInfo(Color.Red); console.log(` Red: name=${redInfo.name}, code=${redInfo.code}`); console.log(` Correct: ${redInfo.name === "Red" && redInfo.code === "#FF0000"}`); // Test 3: Type safety (these would error in real code) console.log("\nTest 3 - Type safety:"); console.log(" ❌ getCSSColor('red') would error"); console.log(" ❌ getCSSColor('RED') would error"); console.log(" ✅ getCSSColor(Color.Red) works"); // Test 4: Enum values can be used in conditions console.log("\nTest 4 - Conditional usage:"); function applyColor(color: Color, element: HTMLElement) { element.style.color = color; } // Test 5: Enum member access console.log("\nTest 5 - Accessing enum values:"); console.log(`Color.Red = ${Color.Red}`); console.log(`Color.Green = ${Color.Green}`); console.log(`Color.Blue = ${Color.Blue}`); ================================================================================ KEY TAKEAWAYS: ================================================================================ ✅ String enums explicitly map names to values ✅ Type-safe: prevents typos and invalid values ✅ Use Record for reverse mapping ✅ Enums work great with switch statements ✅ Alternative: use literal unions for modern code ✅ CSS color codes are perfect use case for enums Common Patterns: - Enum for fixed set of allowed values - Switch statement for handling each case - Record for mapping back to display names - Function parameter with enum type for type safety When to Use: ✅ Status codes, roles, permissions ✅ Color schemes, themes ✅ Direction, orientation, alignment ✅ Severity levels, priorities ✅ State values in state machines When NOT to use: ❌ Arbitrary numbers (just use number type) ❌ Values that change frequently ❌ Values from external APIs (use literal unions instead) ================================================================================