📖 Scenario: You are working on a TypeScript project where you want to create a new type that changes the properties of an existing type based on their value types.For example, you want to make all string properties optional and keep other properties required.
🎯 Goal: Build a mapped type using conditional types that makes all string properties optional and leaves other properties required.
📋 What You'll Learn
Create an interface called Person with properties name (string), age (number), and email (string).
Create a mapped type called OptionalStrings that makes string properties optional and keeps other properties required.
Create a variable person1 of type OptionalStrings and assign it an object with age and email properties.
Print the person1 object to the console.
💡 Why This Matters
🌍 Real World
Mapped types with conditional types help you create flexible and reusable types in TypeScript, useful when working with APIs or complex data models.
💼 Career
Understanding mapped and conditional types is important for TypeScript developers to write clean, maintainable, and type-safe code in professional projects.
Progress0 / 4 steps
1
Create the initial interface
Create an interface called Person with these exact properties: name of type string, age of type number, and email of type string.
Typescript
Hint
Use the interface keyword and define the properties with their types inside curly braces.
2
Create the mapped type with conditional types
Create a mapped type called OptionalStrings that iterates over the keys of Person. Use a conditional type to make properties of type string optional and keep other properties required.
Typescript
Hint
Use [K in keyof Person] to loop over keys and a conditional type with extends string to check the property type.
3
Create a variable using the mapped type
Create a variable called person1 of type OptionalStrings and assign it an object with age set to 30 and email set to "test@example.com". Do not include name property.
Typescript
Hint
Remember that string properties are optional, so you can omit name.
4
Print the variable to the console
Write a console.log statement to print the person1 object.
Typescript
Hint
Use console.log(person1) to display the object.
Practice
(1/5)
1. What does a mapped type with conditional types do in TypeScript? type Example<T> = { [K in keyof T]: T[K] extends string ? number : boolean }
easy
A. It creates a new type where string properties become number and others become boolean.
B. It creates a new type with all properties removed.
C. It changes all properties to string type.
D. It only keeps properties that are strings.
Solution
Step 1: Understand mapped types
Mapped types loop over each key in the original type to create a new type with transformed properties.
Step 2: Apply conditional types
The conditional type checks if the property type extends string; if yes, it changes to number, else to boolean.
Final Answer:
It creates a new type where string properties become number and others become boolean. -> Option A
Quick Check:
Mapped + conditional changes types based on condition [OK]
Thinking it removes properties instead of transforming them
Assuming all types become string
Confusing conditional type logic
2. Which of the following is the correct syntax for a mapped type with a conditional type in TypeScript?
easy
A. type NewType<T> = { [K in T]: T[K] extends number ? string : boolean }
B. type NewType<T> = { [K in keyof T]: T[K] extends number ? string : boolean }
C. type NewType<T> = { [K of keyof T]: T[K] extends number ? string : boolean }
D. type NewType<T> = { K in keyof T: T[K] ? string : boolean }
Solution
Step 1: Check mapped type syntax
The correct syntax uses square brackets with 'in' keyword: [K in keyof T].
Step 2: Verify conditional type usage
The conditional type is written as T[K] extends number ? string : boolean, which is correct.
Final Answer:
type NewType<T> = { [K in keyof T]: T[K] extends number ? string : boolean } -> Option B
Quick Check:
Mapped type syntax = [K in keyof T] [OK]
Hint: Mapped types use [K in keyof T], not 'of' or missing brackets [OK]
Common Mistakes:
Using 'K in T' instead of 'K in keyof T'
Using 'K of keyof T' which is invalid
Missing square brackets around K in mapped type
3. Given the code:
type Flags = { a: string; b: number; c: boolean };
type Result = { [K in keyof Flags]: Flags[K] extends number ? 'num' : 'not-num' };
const test: Result = { a: 'not-num', b: 'num', c: 'not-num' };
What is the type of test.b?
medium
A. 'not-num'
B. number
C. 'num'
D. boolean
Solution
Step 1: Analyze the mapped type Result
For each key in Flags, if the property type is number, Result's property is 'num', else 'not-num'.
Step 2: Check property b in Flags
b is number, so Result['b'] is 'num'.
Final Answer:
'num' -> Option C
Quick Check:
Flags['b'] is number, so Result['b'] = 'num' [OK]
Hint: Check original type, then apply conditional mapping [OK]
Common Mistakes:
Confusing original property type with mapped type
Assuming test.b is number instead of 'num'
Ignoring conditional type logic
4. Identify the error in this mapped type:
type Fix<T> = { [P in keyof T]: T[P] extends string ? number : }
medium
A. Incorrect use of keyof operator
B. Cannot use conditional types inside mapped types
C. Square brackets missing around P
D. Missing type after colon in conditional type
Solution
Step 1: Check conditional type syntax
Conditional types require both true and false branches separated by colon.
Step 2: Identify missing false branch
The code ends with ':' but no type after it, causing syntax error.
Final Answer:
Missing type after colon in conditional type -> Option D
Quick Check:
Conditional types need both branches [OK]
Hint: Conditional types need both true and false parts [OK]
Common Mistakes:
Leaving out false branch in conditional type
Misplacing square brackets in mapped type
Thinking keyof is wrong here
5. How can you create a mapped type that keeps only the keys of an object whose values are assignable to a specific type, for example, only keys with string values? Choose the correct mapped type:
hard
A. type FilterStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] }
B. type FilterStrings<T> = { [K in keyof T]: T[K] extends string ? never : K }
C. type FilterStrings<T> = { [K in keyof T]: T[K] extends string ? string : never }
D. type FilterStrings<T> = { [K in keyof T]: K extends string ? T[K] : never }
Solution
Step 1: Understand key remapping in mapped types
Using 'as' allows filtering keys by condition, replacing keys with 'never' to omit them.
Step 2: Check each option
type FilterStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] } correctly uses 'as' with conditional to keep keys where T[K] extends string; others become never (excluded).
Final Answer:
type FilterStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] } -> Option A
Quick Check:
Key remapping with 'as' filters keys [OK]
Hint: Use 'as' with conditional to filter keys in mapped types [OK]
Common Mistakes:
Not using 'as' for key filtering
Returning never as value instead of key
Confusing key and value conditions
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.