Mapped Types & Template Literal Types

0/5 in this phase0/21 across the roadmap

📖 Concept

Mapped types iterate over keys of a type and transform each property — they're the for...in loop of the type system. All utility types like Partial, Readonly, and Pick are built with mapped types.

Syntax: { [K in keyof T]: NewType }

Key modifiers:

  • ? / -? — Add or remove optional
  • readonly / -readonly — Add or remove readonly
  • as NewKey — Remap keys (TS 4.1+)

Template literal types bring string manipulation to the type level: \hello-${string}``. Combined with unions, they generate all string combinations at compile time.

Key template literal utilities: Uppercase, Lowercase, Capitalize, Uncapitalize

Mapped types + template literals together enable extremely powerful patterns:

  • Generating getter/setter method names from property names
  • Creating event name types from state keys
  • Building CSS class name types
  • Type-safe i18n keys

🏠 Real-world analogy: Mapped types are like a stamping machine on an assembly line. Each item (property) that passes through gets the same modification (transformation). Template literal types are like a label printer — you feed in variables and get formatted labels.

💻 Code Example

codeTap to expand ⛶
1// Basic mapped type (how Partial works internally)
2type MyPartial<T> = {
3 [K in keyof T]?: T[K];
4};
5
6// Remove optional (Required internally)
7type MyRequired<T> = {
8 [K in keyof T]-?: T[K];
9};
10
11// Make all properties readonly
12type MyReadonly<T> = {
13 readonly [K in keyof T]: T[K];
14};
15
16// Remove readonly
17type Mutable<T> = {
18 -readonly [K in keyof T]: T[K];
19};
20
21// Transform value types
22type Stringify<T> = {
23 [K in keyof T]: string;
24};
25type Nullify<T> = {
26 [K in keyof T]: T[K] | null;
27};
28
29// ⭐ Key remapping with 'as' (TS 4.1+)
30interface User {
31 name: string;
32 age: number;
33 email: string;
34}
35
36// Generate getter names
37type Getters<T> = {
38 [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
39};
40type UserGetters = Getters<User>;
41// { getName: () => string; getAge: () => number; getEmail: () => string }
42
43// Generate event handler names
44type OnChangeHandlers<T> = {
45 [K in keyof T as `on${Capitalize<string & K>}Change`]: (value: T[K]) => void;
46};
47type UserHandlers = OnChangeHandlers<User>;
48// { onNameChange: (value: string) => void; onAgeChange: ... }
49
50// Filter keys by value type
51type StringKeysOnly<T> = {
52 [K in keyof T as T[K] extends string ? K : never]: T[K];
53};
54type StringProps = StringKeysOnly<User>;
55// { name: string; email: string } (age removed!)
56
57// Template literal types
58type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
59type ApiRoute = `/api/${string}`;
60type TypedRoute = `/api/${"users" | "posts" | "comments"}`;
61// "/api/users" | "/api/posts" | "/api/comments"
62
63// Cartesian product with template literals
64type Color = "red" | "blue" | "green";
65type Size = "sm" | "md" | "lg";
66type ClassName = `${Color}-${Size}`;
67// "red-sm" | "red-md" | "red-lg" | "blue-sm" | ... (9 combinations)
68
69// Built-in string transformers
70type Greeting = "hello world";
71type Upper = Uppercase<Greeting>; // "HELLO WORLD"
72type Lower = Lowercase<"HELLO">; // "hello"
73type Cap = Capitalize<"hello">; // "Hello"
74type Uncap = Uncapitalize<"Hello">; // "hello"
75
76// Practical: derive event names from object keys
77type EventNames<T> = {
78 [K in keyof T]: `on${Capitalize<string & K>}`;
79}[keyof T];
80type UserEvents = EventNames<User>;
81// "onName" | "onAge" | "onEmail"

🏋️ Practice Exercise

Mini Exercise:

  1. Implement MyPick<T, K> using a mapped type
  2. Create Nullable<T> that makes all properties T[K] | null
  3. Use key remapping to create Setters<T>setName(value: string): void
  4. Build a template literal type for CSS utility classes like "text-sm", "bg-red", etc.
  5. Create FilterByType<T, U> that keeps only properties of type U

⚠️ Common Mistakes

  • Forgetting string & K when using Capitalize in key remapping — keyof T can include symbol, which can't be capitalized

  • Not understanding that mapped types create NEW types — they don't modify the original; types are always immutable

  • Using as never in key remapping to filter — this is correct behavior (never keys are removed), but it's confusing at first

  • Template literal type explosion — combining large unions creates a cartesian product that can slow the compiler

  • Confusing mapped types with index signatures — { [K in keyof T]: T[K] } iterates known keys; { [key: string]: T } accepts any string key

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for Mapped Types & Template Literal Types