Discover how a single line of code can replace dozens of repetitive property definitions!
Why Mapped type with template literals in Typescript? - Purpose & Use Cases
Imagine you have many object properties and you want to create new property names by adding prefixes or suffixes manually for each one.
For example, if you have properties like name and age, you want to create getName, setName, getAge, setAge by hand.
Doing this manually means writing repetitive code for each property, which is slow and easy to make mistakes.
It's hard to keep track of all variations and update them if the original properties change.
Mapped types with template literals let you automatically create new property names by combining strings and existing keys.
This means you write one simple rule, and TypeScript generates all the new properties for you, saving time and avoiding errors.
interface Person {
name: string;
age: number;
}
interface PersonMethods {
getName(): string;
setName(value: string): void;
getAge(): number;
setAge(value: number): void;
}type Person = {
name: string;
age: number;
};
type PersonMethods = {
[K in keyof Person as `get${Capitalize<string & K>}`]: () => Person[K];
} & {
[K in keyof Person as `set${Capitalize<string & K>}`]: (value: Person[K]) => void;
};You can create flexible, consistent, and scalable object types that automatically adapt when your base properties change.
When building a form library, you can automatically generate getter and setter methods for each form field without writing each one manually.
Manual property renaming is repetitive and error-prone.
Mapped types with template literals automate property name creation.
This leads to cleaner, safer, and easier-to-maintain code.
Practice
What does a mapped type with template literals in TypeScript allow you to do?
Example: { [K in keyof T as `get${Capitalize}`]: () => T[K] }
Solution
Step 1: Understand mapped types
Mapped types create new object types by transforming keys or values of an existing type.Step 2: Role of template literals
Template literals let you rename keys dynamically by combining strings and key names.Final Answer:
Rename keys dynamically in object types -> Option BQuick Check:
Mapped type + template literals = dynamic key renaming [OK]
- Confusing runtime behavior with type transformations
- Thinking it changes object values instead of keys
- Assuming it creates variables or runs code
Which of the following is the correct syntax to rename keys using a mapped type with template literals?
type RenameKeys<T> = { [K in keyof T as ???]: T[K] }Solution
Step 1: Understand key remapping syntax
Useaswith template literals and intersect key type withstringto ensure keys are strings.Step 2: Check each option
`new_${string & K}` usesstring & Kwhich is correct; others use incorrect types likenumberorany.Final Answer:
`new_${string & K}` -> Option AQuick Check:
Usestring & Kfor safe key renaming [OK]
- Using K directly without string intersection
- Using number or any instead of string & K
- Missing backticks for template literals
What is the resulting type of the following code?
type User = { name: string; age: number };
type PrefixedUser = { [K in keyof User as `get${Capitalize}`]: () => User[K] };Solution
Step 1: Analyze key transformation
Keys 'name' and 'age' are capitalized and prefixed with 'get', becoming 'getName' and 'getAge'.Step 2: Analyze value transformation
Values become functions returning the original property types: () => string and () => number.Final Answer:
{ getName: () => string; getAge: () => number } -> Option DQuick Check:
Mapped keys capitalized + function values = { getName: () => string; getAge: () => number } [OK]
- Not capitalizing keys
- Returning values instead of functions
- Using original keys without prefix
Identify the error in this mapped type using template literals:
type Flags = { isActive: boolean; isAdmin: boolean };
type PrefixedFlags = { [K in keyof Flags as `flag_${K}`]: Flags[K] };Solution
Step 1: Check key remapping syntax
Template literal keys must intersect K with string:string & Kto ensure keys are strings.Step 2: Identify missing intersection
The code uses`flag_${K}`withoutstring & K, causing a type error.Final Answer:
Missing string intersection with K in template literal -> Option CQuick Check:
Usestring & Kin template literals to fix error [OK]
- Omitting string & K intersection
- Thinking Capitalize is mandatory
- Believing template literals can't be used here
Given this type, how would you create a mapped type that prefixes keys with on and capitalizes them, but only for keys starting with handle?
type Handlers = { handleClick: () => void; handleHover: () => void; reset: () => void };Solution
Step 1: Filter keys starting with 'handle'
Use conditional typeK extends `handle${string}`to select only keys starting with 'handle'.Step 2: Rename keys with 'on' prefix and capitalize
Use template literal`on${Capitalize}`to rename keys accordingly.Step 3: Assign original value types
Keep the original function types fromHandlers[K].Final Answer:
type Prefixed = { [K in keyof Handlers as K extends `handle${string}` ? `on${Capitalize}` : never]: Handlers[K] }; -> Option AQuick Check:
Conditional key remapping with prefix and capitalize = type Prefixed = { [K in keyof Handlers as K extends `handle${string}` ? `on${Capitalize}` : never]: Handlers[K] }; [OK]
- Not filtering keys by prefix
- Applying rename to all keys
- Incorrect conditional syntax
Ready to prove it?
Pass the test and this pattern moves unknown
