CHALLENGE 3: Generic with Constraint ===================================== SOLUTION: function getProp(obj: T, key: K): T[K] { return obj[key]; } // Testing: const person = { name: "Alice", age: 30, email: "alice@example.com" }; // ✅ Valid keys: getProp(person, "name"); // Returns string getProp(person, "age"); // Returns number getProp(person, "email"); // Returns string // ❌ Invalid keys (TypeScript error): getProp(person, "phone"); // Error! "phone" is not a key of person EXPLANATION: - "function getProp" — two type parameters - T: the object type - K: a key of T (constrained by "extends keyof T") - "keyof T" means "any key that exists on T" - "T[K]" means "the type of the value at key K" - When you call getProp(person, "name"): - T becomes the type of person - K becomes "name" (and it's valid because person has 'name') - Return type is T["name"] = string WHY THIS MATTERS: ✅ Type-safe property access ✅ Prevents accessing non-existent keys ✅ Return type matches the property type ✅ IDE autocomplete shows only valid keys ALTERNATIVE: For different return types function getProp(obj: T, key: K): T[K] { return obj[key]; } interface Config { apiUrl: string; port: number; debug: boolean; } const config: Config = { apiUrl: "https://api.example.com", port: 3000, debug: true }; const url = getProp(config, "apiUrl"); // string const port = getProp(config, "port"); // number const debug = getProp(config, "debug"); // boolean // Each return type is inferred correctly! TESTING TYPE ERRORS: // This would cause a TypeScript error: getProp(config, "timeout"); // Error! 'timeout' is not a key of Config // This would also error: const obj = { name: "Bob" }; getProp(obj, "age"); // Error! 'age' is not a key of obj ADVANCED PATTERN: Getting multiple properties function getProps(obj: T, ...keys: K[]): T[K][] { return keys.map(key => obj[key]); } const values = getProps(person, "name", "email"); // Returns [string, string] KEY INSIGHT: Generic constraints ensure type safety without losing flexibility. You write one function that works with any object, but TypeScript prevents you from accessing keys that don't exist.