TypeScript for a long time allowed describing literal types for individual string or numeric values, but with the advent of template literals there arose a need to type specific string patterns. Template Literal Types add the ability to describe types based on template string concatenation, providing static validation of the structure of string values.
It is impossible to check if a string conforms to a certain format (e.g., 'user_42') using ordinary string types — they are too general. Without template types, the compiler cannot guarantee that the string will fit into a strictly defined pattern.
Template Literal Types allow forming complex string types at compile time and ensure strict checking of their conformity to specific patterns.
Example code:
type UserId = `user_${number}`; function loadUser(id: UserId) { // ... } loadUser('user_123'); // correct loadUser('admin_123'); // compilation error
Key features:
Can Template Literal Types only be used with number/literal? Can custom string literals be used in the template?
Any literal type can be used — strings, numbers, unions:
type EventType = `event_${'click' | 'hover'}`; // event_click | event_hover
Can a regular string be passed if the function expects a Template Literal type?
No, if the type explicitly expects a template literal, just string will not do:
function handler(type: `btn_${string}`) {} handler('btn_click'); // ok handler('button'); // compilation error
Do template string types work with mapped types and keyof?
Yes, Template Literal Types work well with mapped types and object keys:
const colors = {red: 1, blue: 2}; type ColorKey = keyof typeof colors; type ColorClass = `color-${ColorKey}`; // color-red | color-blue
An API takes identifiers of the form 'user_XXX', the function is untyped — any string can be submitted, leading to bugs on the server in case of errors.
Pros:
Cons:
The type UserId = user_${number} is used, ensuring the correctness of function arguments and safe requests to the server prior to compilation.
Pros:
Cons: