SOLUTION: Challenge 2 - Intersection & Custom Guard ==================================================== Challenge: Create two interfaces (Admin and Employee), then a type for a value that is both. Write a custom type guard function to check if something is an Admin. --- SOLUTION: interface Employee { id: number; name: string; department: string; } interface Admin { isAdmin: true; permissions: string[]; } type AdminEmployee = Employee & Admin; // Custom type guard: "value is Admin" tells TypeScript to narrow the type function isAdmin(person: Employee | Admin): person is Admin { return "permissions" in person && "isAdmin" in person; } // Alternative: more explicit check function isAdminStrict(person: any): person is Admin { return ( typeof person.isAdmin === "boolean" && person.isAdmin === true && Array.isArray(person.permissions) ); } // Test cases const employee: Employee = { id: 1, name: "Bob", department: "Engineering" }; const adminEmployee: AdminEmployee = { id: 2, name: "Alice", department: "Engineering", isAdmin: true, permissions: ["delete_users", "view_logs", "manage_settings"] }; // Use the type guard if (isAdmin(employee)) { console.log(`${employee.name} has permissions:`, employee.permissions); } else { console.log(`${employee.name} is not an admin`); } if (isAdmin(adminEmployee)) { console.log(`${adminEmployee.name} has permissions:`, adminEmployee.permissions); } else { console.log(`${adminEmployee.name} is not an admin`); } --- EXPLANATION: 1. INTERSECTION (&): AdminEmployee must have ALL properties from both Employee AND Admin. It's not just one or the other — it's everything from both. 2. CUSTOM TYPE GUARD: The function signature "person is Admin" is a type predicate. It tells TypeScript: "If this function returns true, treat person as an Admin." 3. GUARD LOGIC: We check for properties that only Admin has ("permissions", "isAdmin"). The "in" operator checks if a property exists on an object. 4. NARROWING: After the guard succeeds (returns true), TypeScript treats person as Admin. After it fails (returns false), TypeScript narrows it to the remaining type. WHY THIS PATTERN: Intersections are powerful for combining capabilities. Type guards with "is" predicates are the type-safe way to express "this value definitely matches a narrower type." This is safer than type casting (as Admin) because it enforces runtime validation.