← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Mapped Types & Template Literal Types

TypeScript 2.1 Advanced
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list TypeScript (the type checker) and ESLint as tools. The code_pattern describes manually duplicating interfaces instead of using Partial<T> or built-in utility types — TypeScript's compiler won't error on this duplication, but a specialist TypeScript-aware linter rule (e.g. @typescript-eslint) or careful review would catch redundant parallel type definitions. It won't surface as a compiler error (not d1/d3), but TypeScript itself as a type-checking tool sits at d5.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix says to use built-in utility types (Partial<T>, Required<T>, etc.) before writing custom mapped types. Replacing a manually duplicated interface with Partial<T> or another utility type is a small, localised refactor — more than a one-liner swap in practice because it may involve multiple property definitions, but it stays within one component/file, placing it at e3.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Mapped types apply to web and cli contexts broadly, but their burden is scoped to the type layer of TypeScript — misuse (over-engineering or manual duplication) primarily taxes the module or component where the types are defined. Other parts of the codebase are largely unaffected unless the types are shared widely. This keeps the structural debt localised rather than system-wide.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception field identifies a real but learnable gotcha: developers assume mapped types are only for utility types like Partial, missing their full power to rename keys, filter by constraint, and generate derivative types. Additionally, common_mistakes include forgetting -? for Required<T>, misusing as clause, and applying template literal types to non-string unions — these are documented gotchas that most developers encounter once and learn, fitting the t5 anchor well.

About DEBT scoring →

Also Known As

mapped types template literal types TypeScript type transformation

TL;DR

Mapped types transform existing types by iterating over their keys. Template literal types create string union types from combinations — together they enable powerful type-level transformations.

Explanation

Mapped types: { [K in keyof T]: NewType } — iterate over all keys of T and transform their value types. Used to build Partial, Readonly, Required, and Record. Modifiers: +/- to add/remove optional (?) and readonly. Template literal types: `${Prefix}${string}` — create string union types by combining other string types. Applications: EventName as `on${Capitalize<Event>}`, getter names as `get${Capitalize<K>}`, CSS property names. Combined: transform an object type's method names into event handler names automatically.

Common Misconception

Mapped types are only for utility types like Partial — mapped types can transform any aspect of a type: rename keys, change value types, filter keys by constraint, and generate derivative types.

Why It Matters

Without mapped types, you manually maintain parallel type definitions that drift apart — mapped types derive one type from another, ensuring they always stay in sync.

Common Mistakes

  • Forgetting -? to remove optionality in mapped types — Required<T> needs -? modifier.
  • Not using as clause for key remapping — available in TS 4.1+ for key transformation.
  • Template literal types on non-string unions — only string literal unions work.
  • Over-engineering with complex mapped types when a simpler type works.

Code Examples

✗ Vulnerable
// Manually maintained parallel types — drift risk:
type User = { name: string; email: string; age: number; };
// Must update this manually every time User changes:
type UserGetters = {
    getName: () => string;
    getEmail: () => string;
    getAge: () => number;
};
✓ Fixed
// Mapped type derives UserGetters automatically:
type User = { name: string; email: string; age: number; };

type Getters<T> = {
    [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type UserGetters = Getters<User>;
// Equivalent to:
// { getName: () => string; getEmail: () => string; getAge: () => number; }

// Template literal type for event names:
type EventName = 'click' | 'focus' | 'blur';
type Handler = `on${Capitalize<EventName>}`;  // 'onClick' | 'onFocus' | 'onBlur'

Added 16 Mar 2026
Edited 22 Mar 2026
Views 62
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 2 pings T 0 pings F 0 pings S 3 pings S 1 ping M 0 pings T 1 ping W 0 pings T 2 pings F 0 pings S 2 pings S 3 pings M 1 ping T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 9 Perplexity 8 ChatGPT 8 Scrapy 6 Google 5 Ahrefs 4 Unknown AI 4 Claude 2 SEMrush 2 Meta AI 1 Bing 1 PetalBot 1
crawler 46 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Use Partial<T>, Required<T>, Readonly<T>, Record<K,V>, Pick<T,K>, and Omit<T,K> from TypeScript's built-in utility types before writing your own mapped types
📦 Applies To
typescript 2.1 web cli
🔗 Prerequisites
🔍 Detection Hints
Manually duplicating interface with optional properties when Partial<T> would work; custom mapped type re-implementing built-in utility types
Auto-detectable: ✓ Yes typescript eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File


✓ schema.org compliant