Template Literal Types
Build string literal types by interpolation — typed string patterns at compile time.
Template literal types use backtick syntax in type position to compose string literals, exactly mirroring template strings in values.
type Lang = "en" | "fr";
type Greeting = `hello_${Lang}`; // "hello_en" | "hello_fr"Feed a union in and the type expands across every combination — a small pattern that generates a lot of precise literal types.
Intrinsic string helpers
TypeScript ships four built-ins for casing: Uppercase, Lowercase, Capitalize, and Uncapitalize. They pair beautifully with template literals to model naming conventions:
type EventName<K extends string> = `on${Capitalize<K>}`;
type T = EventName<"click">; // "onClick"This is what lets libraries type things like CSS units (`${number}px`), event handler names, and API route strings.
Example
When to use it
- An event system builds typed event names like 'on:click' | 'on:focus' by template-literal-concatenating a prefix with a union.
- A CSS-in-TypeScript library generates typed property accessor strings like 'margin-top' from separate scale and direction unions.
- A routes object uses template literal types to enforce that every route string starts with a slash.
More examples
Concatenate string literals
Defines a template literal type as a pattern; only strings that match the interpolated shape are assignable.
type Greeting = `Hello, ${string}!`;
const a: Greeting = 'Hello, Alice!'; // OK
const b: Greeting = 'Hi, Alice!'; // Error: does not match patternUnion distribution in template
Template literal types distribute over union members, generating every combination of prefix and side automatically.
type Side = 'top' | 'bottom' | 'left' | 'right';
type Prop = `margin-${Side}` | `padding-${Side}`;
// 'margin-top' | 'margin-bottom' | ... | 'padding-right'
function setStyle(prop: Prop, value: string): void {
console.log(`${prop}: ${value}`);
}Event name builder
Combines Capitalize<T> with a template literal to derive typed event handler names, and uses key remapping to build the map.
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<'click'>; // 'onClick'
type ChangeEvent = EventName<'change'>; // 'onChange'
type HandlerMap = {
[K in 'click' | 'change' | 'focus' as EventName<K>]: () => void;
};
Discussion