C.W.K.
Stream
Lesson 05 of 06 · published

Template Literal Types

~9 min · type-manipulation, template-literals, string-manipulation

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"String concatenation in the type layer. Combined with mapped types, it builds key transformations."

Template literal types

Template literal types use the same backtick syntax as runtime template literals, but they operate on string-literal types. `Hello, ${string}` is a type that matches any string starting with 'Hello, '. `${'a' | 'b'}-${1 | 2}` is the union of 'a-1' | 'a-2' | 'b-1' | 'b-2'.

This is type-level string manipulation. The compiler can concatenate, pattern-match, and union string literals at the type level — and combined with key remapping in mapped types, you can transform property names systematically.

Built-in string utility types

TypeScript ships four built-ins for case manipulation:

  • Uppercase<S>
  • Lowercase<S>
  • Capitalize<S> — uppercase first letter
  • Uncapitalize<S> — lowercase first letter

Combined with template literals, these let you build types like 'event handler names': `on${Capitalize<EventName>}` — from a union of event names like 'click' | 'hover', you get 'onClick' | 'onHover'.

Where template literal types win

The classic use is library APIs that derive method names from data shapes. React's useState setter is one: from a hook named useUser, the setter is conventionally setUser. Template literal types let library authors express this as a type — and the compiler verifies the convention is followed.

Template literal types are how libraries derive APIs at the type level. When you see on${Capitalize<...>} in a library's types, it's building event-handler names from event types — and the compiler is checking your code uses the right names.

Code

Template literal types — concat, distribute, case-transform·typescript
// Basic template literal types.
type Greeting = `Hello, ${string}`;
const g1: Greeting = 'Hello, Pippa';   // ✅
const g2: Greeting = 'Hi there';        // ❌ doesn't start with 'Hello, '

// Union distribution.
type CSSValue = `${number}px` | `${number}rem` | `${number}%`;
const v: CSSValue = '12px';            // ✅
const v2: CSSValue = '1.5rem';         // ✅

// Cartesian product.
type Suit = 'hearts' | 'spades' | 'diamonds' | 'clubs';
type Rank = 'A' | 'K' | 'Q' | 'J';
type Card = `${Rank}-of-${Suit}`;       // 16 literal types total

// Built-in case utilities.
type A = Uppercase<'hello'>;            // 'HELLO'
type B = Capitalize<'name'>;            // 'Name'

// Event handler names from event names.
type EventName = 'click' | 'hover' | 'focus';
type Handler = `on${Capitalize<EventName>}`;
// 'onClick' | 'onHover' | 'onFocus'

External links

Exercise

Given type Method = 'GET' | 'POST' | 'PUT' | 'DELETE', build type Handler = 'handleGet' | 'handlePost' | 'handlePut' | 'handleDelete'. Then build type Action = '${Method}_USER' | '${Method}_POST' — the cartesian product of methods and entities.
Hint
type Handler = `handle${Capitalize<Lowercase<Method>>}` — lowercase the method first, then capitalize the first letter. Cartesian product is just two template literals in one type.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.