Template literal types use backtick syntax at the type level to construct string types from other types — combined with union distribution they generate combinatorial patterns, and with intrinsic string types (Uppercase, Lowercase, Capitalize) they enable type-safe event handlers, CSS values, and API routes.
Backtick types interpolate other types — `on${string}` matches onClick, onScroll, etc. ${string} and ${number} are wildcard matchers.
Unions in template positions produce all combinations — `${A | B}-${X | Y}` creates four string types from two unions.
Uppercase, Lowercase, Capitalize, and Uncapitalize transform string literal types — built into the compiler for case conversion.
Pattern-match and extract substrings from string types — enables type-safe routing, event handler typing, and string transformation at the type level.
Template literal types (TypeScript 4.1) bring JavaScript's template string syntax to the type level. They construct new string literal types by interpolating other types into a template.
Template literal types use the same backtick syntax as JavaScript template strings, but at the type level:
type Greeting = `Hello, ${string}`; // matches any string starting with "Hello, "
type Port = `${number}`; // matches any numeric string
type EventName = `on${string}`; // matches onClick, onScroll, etc.The ${string} and ${number} placeholders match any string or numeric string respectively.
When a union type is interpolated, the template distributes over each member, producing all combinations:
type Color = 'red' | 'blue';
type Size = 'sm' | 'lg';
type ClassName = `${Size}-${Color}`;
// 'sm-red' | 'sm-blue' | 'lg-red' | 'lg-blue'This combinatorial expansion is powerful for generating all valid string patterns from a set of components. Multiple union positions multiply together.
TypeScript provides four built-in types for transforming string literal types:
Uppercase<T> — Uppercase<'hello'> → 'HELLO'Lowercase<T> — Lowercase<'HELLO'> → 'hello'Capitalize<T> — Capitalize<'hello'> → 'Hello'Uncapitalize<T> — Uncapitalize<'Hello'> → 'hello'These are "intrinsic" — they're implemented in the compiler, not in TypeScript code.
Event handler types:
type Events = 'click' | 'focus' | 'blur';
type Handlers = `on${Capitalize<Events>}`; // 'onClick' | 'onFocus' | 'onBlur'CSS utility classes:
type Spacing = 1 | 2 | 4 | 8;
type Direction = 't' | 'r' | 'b' | 'l';
type SpacingClass = `p${Direction}-${Spacing}`; // 'pt-1' | 'pt-2' | ... 'pl-8'API route patterns:
type ApiRoute = `/api/${string}`;
type UserRoute = `/api/users/${number}`;Template literal types combine with conditional types and infer for string parsing:
type ExtractParam<T> = T extends `${string}:${infer P}/${string}` ? P : never;
type Param = ExtractParam<'/api/:userId/posts'>; // 'userId'This pattern-matches against string types and extracts substrings — it's how type-safe routing libraries (like tRPC and Hono) extract route parameters at the type level.
Combined with recursive conditional types, template literals enable complex string transformations:
type CamelCase<S extends string> =
S extends `${infer Head}_${infer Tail}`
? `${Head}${Capitalize<CamelCase<Tail>>}`
: S;
type Result = CamelCase<'hello_world_foo'>; // 'helloWorldFoo'Template literal types construct string types using backtick syntax with type interpolation. Unions in templates distribute to produce all combinations. Intrinsic types (Uppercase, Capitalize) transform string cases. Combined with infer, they enable type-level string parsing for routes, event names, and CSS utilities. Libraries like tRPC use these for type-safe API routes.
Fun Fact
Template literal types enabled an explosion of type-level programming in the TypeScript ecosystem. Developers have built type-level SQL parsers, JSON parsers, CSS type checkers, and even a type-level regex engine — all using template literal types with recursive conditional types. The TypeScript team had to add recursion depth limits to prevent the compiler from hanging on these creative (ab)uses.