SOLUTION: Challenge 3 - Mapped Type ==================================== Challenge: Take any interface and create a mapped type that makes all properties optional AND readonly. Test it with a sample object. --- SOLUTION: interface User { id: number; name: string; email: string; age: number; } // Mapped type: iterate over all keys and make them optional & readonly type ReadOnlyPartial = { readonly [K in keyof T]?: T[K]; }; // Apply it to User type UserReadOnlyPartial = ReadOnlyPartial; // This is equivalent to: // { // readonly id?: number; // readonly name?: string; // readonly email?: string; // readonly age?: number; // } // Test it with a sample object const config: UserReadOnlyPartial = { id: 1, name: "Alice" // age and email are optional, so we don't need them }; // Try to modify (this will fail at compile time) // config.name = "Bob"; // ❌ Error: Cannot assign to readonly property // config.newProp = "x"; // ❌ Error: Object is not extensible console.log(config.name); // ✅ Reading is fine --- ALTERNATIVE: Separate Readonly and Partial If you want to see them separately: // Make all properties readonly type ReadOnly = { readonly [K in keyof T]: T[K]; }; // Make all properties optional type Partial = { [K in keyof T]?: T[K]; }; // Then combine them type ReadOnlyPartial = ReadOnly>; --- EXPLANATION: KEYOF: keyof User → "id" | "name" | "email" | "age" Gets all property names as a union. IN (iteration): [K in keyof T] iterates over each property name. K becomes "id", then "name", then "email", etc. OPTIONAL (?): T[K]? makes the property optional. READONLY: readonly makes the property immutable. T[K]: Accesses the type of property K in the original type. For "id", T["id"] → number For "name", T["name"] → string RESULT: Every property from the original type is copied over, but optional and readonly. --- ADVANCED: TypeScript has built-in utility types that do similar things: // TypeScript provides these out-of-the-box: type PartialUser = Partial; type ReadOnlyUser = Readonly; type PartialReadOnlyUser = Readonly>; // You can use these instead of writing your own mapped types every time. // But understanding how to build them yourself is crucial for mastery. --- WHY THIS PATTERN MATTERS: 1. DRY (Don't Repeat Yourself): Write the transformation once, use it everywhere. 2. Consistency: All properties are transformed the same way. 3. Maintainability: If User gets new properties, ReadOnlyPartial automatically applies the transformation to them. 4. Type Safety: No need to manually write optional/readonly for each property.