Mapped type with template literals in Typescript - Time & Space Complexity
We want to understand how the time it takes to create a new type grows when using mapped types with template literals in TypeScript.
Specifically, how does the process scale as the number of keys increases?
Analyze the time complexity of the following code snippet.
type Options = "width" | "height" | "color";
type PrefixedOptions = {
[K in Options as `get${Capitalize}`]: () => string;
};
This code creates a new type by taking each key from Options, capitalizing it, and prefixing it with "get" to form new keys.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Iterating over each key in the union
Options. - How many times: Once for each key in
Options(3 times in this example).
As the number of keys in the original type grows, the mapped type processes each key once to create a new key.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 |
| 100 | 100 |
| 1000 | 1000 |
Pattern observation: The number of operations grows directly with the number of keys, increasing in a straight line.
Time Complexity: O(n)
This means the time to create the mapped type grows linearly with the number of keys in the original type.
[X] Wrong: "The mapped type runs in constant time no matter how many keys there are."
[OK] Correct: Each key must be processed individually to create the new keys, so more keys mean more work.
Understanding how mapped types scale helps you reason about type transformations and their impact on compile-time performance, a useful skill in real projects.
"What if we added nested mapped types inside the template literal? How would the time complexity change?"
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
