Template Literal Types
Strings you can compute
Section titled “Strings you can compute”Template literal types look like JavaScript template strings, but they build types. You interpolate other types into a string-shaped type:
type Greeting = `Hello, ${string}`;
const a: Greeting = "Hello, Ada"; // ✅const b: Greeting = "Hi, Ada"; // ❌ must start with "Hello, "Interpolate a literal union and the template distributes over it — producing every combination as a union of literal types:
type Lang = "en" | "th";type Kind = "page" | "post";
type Key = `${Lang}-${Kind}`;// ^? "en-page" | "en-post" | "th-page" | "th-post"Two unions of two members give four literal types. This is how libraries generate exact string keys — CSS properties, event names, i18n keys — with zero runtime code.
The intrinsic string manipulators
Section titled “The intrinsic string manipulators”TypeScript ships four built-in types that transform string literal types: Uppercase, Lowercase, Capitalize, and Uncapitalize.
type Loud = Uppercase<"hello">; // "HELLO"type Cap = Capitalize<"name">; // "Name"
// Combine with a template to build event handler namestype Handler<E extends string> = `on${Capitalize<E>}`;type ClickHandler = Handler<"click">; // "onClick"flowchart LR u["union: en or th"] -->|"interpolate into 'X-page'"| out["en-page or th-page"]
Pattern matching with infer
Section titled “Pattern matching with infer”The real power arrives when you combine template literals with a conditional type and infer: you can destructure a string type, capturing part of it into a new type variable.
// Capture the event name after the "on" prefixtype EventName<T> = T extends `on${infer E}` ? E : never;
type E1 = EventName<"onClick">; // "Click"type E2 = EventName<"onHover">; // "Hover"type E3 = EventName<"click">; // never — no "on" prefix
// Split a route into its partstype Method<T> = T extends `${infer M} ${string}` ? M : never;type M = Method<"GET /users">; // "GET"infer E says “match anything here and call it E.” This is genuine parsing at the type level — the technique behind typed routers that extract :id params from a path string and libraries that validate format strings.
Where this shows up
Section titled “Where this shows up”- Typed keys:
`${Theme}-${Shade}`for a design-token type. - Event maps: turning
"click"into"onClick"for prop types. - Route params: extracting
idfrom"/users/:id"into{ id: string }. - ORM/query builders: parsing a column string into a typed shape.
Use it where a string genuinely encodes structure. Reach for it too eagerly and you get types no teammate can read — the recurring trade-off of type-level programming.