Skip to main content

TS Ep 47: Template Literal Types

Rachmat Hidayat
Author
Rachmat Hidayat
Learn & sharing insights on TypeScript, Go, Kubernetes, DevOps, DevSecOps, SRE, Platform Engineering, AI/ML Engineering, and MLOps.
typescript - This article is part of a series.
Part 47: This Article
Instead of hardcoding dozens of repetitive string literal variations, you can generate them dynamically using Template Literal Types. This feature brings the flexibility of JavaScript’s backtick strings directly into the TypeScript compiler.

1. The Basics
#

Template literal types use the exact same backtick syntax as JavaScript template strings, but instead of injecting runtime variables, they inject literal types or unions.

type World = "world";

// 🟢 Computes to exactly "hello world"
type Greeting = `hello ${World}`; 

You can inject string, number, boolean, or bigint into template literal types.

type Version = `v${number}.${number}.${number}`;

const valid: Version = "v1.4.2";
// const invalid: Version = "v1.4.x"; // Error!

(Note: While Version accepts “v1.4.2”, due to current compiler limitations, number inside template literals accepts broad numeric representations, not strictly bounded digits, but it prevents alphabetical characters).


2. Union Permutations (The Magic Multiplier)
#

The true power of Template Literal Types unlocks when you inject a Union Type. When you interpolate a union into a template literal, TypeScript automatically distributes it and generates every possible combinatorial permutation.

Imagine you are building a UI library (like Tailwind or Bootstrap) and you need to type-check class names constructed from color and size modifiers.

type Color = "red" | "blue" | "green";
type Size = "sm" | "md" | "lg";

// 🟢 Generates 9 unique string literals instantly!
type ButtonClass = `btn-${Color}-${Size}`;

/* Inferred Union:
  | "btn-red-sm"   | "btn-red-md"   | "btn-red-lg"
  | "btn-blue-sm"  | "btn-blue-md"  | "btn-blue-lg"
  | "btn-green-sm" | "btn-green-md" | "btn-green-lg"
*/

function renderButton(className: ButtonClass) {
  // ...
}

renderButton("btn-blue-md"); // Valid
// renderButton("btn-yellow-sm"); // Compiler Error!
Warning

Be careful with Combinatorial Explosion. If you intersect five unions that each have 10 members, TypeScript will generate 100,000 unique strings and likely crash your editor’s language server!


3. Parsing Strings with infer
#

Template literals combined with the infer keyword (from Episode 44) turn TypeScript into a powerful, type-safe string parser.

Splitting by Delimiters (Email Parsing)
#

You can use template literals to split strings by a specific character (like @) and extract the resulting halves into type variables!

// Pattern Match: Does T look like "Something @ SomethingElse"?
type ExtractDomain<TEmail> = 
  TEmail extends `${infer User}@${infer Domain}` 
    ? Domain 
    : never;

type MyDomain = ExtractDomain<"contact@rhidayat.work">; 
// Inferred Type: "rhidayat.work"

Route Parameter Parsing
#

Modern full-stack frameworks (like Next.js or tRPC) use this exact technique to provide strict autocompletion for URL paths.

If you have a string that represents a route "/users/:id", you can extract the parameter name:

type ExtractParam<TRoute> = 
  TRoute extends `/api/${infer Entity}/:${infer ParamId}` 
    ? { entity: Entity, param: ParamId } 
    : never;

type RouteData = ExtractParam<"/api/posts/:postId">; 
/* Inferred Type: 
{ 
  entity: "posts", 
  param: "postId" 
} 
*/

Template literals are arguably the most impressive feat of engineering in the modern TypeScript compiler, enabling highly robust typing for routing libraries, event emitters, and CSS-in-JS frameworks.


Summary & Next Steps
#

In this episode:

  • We injected literal types into strings using `template ${Type}`.
  • We utilized Union Permutation to generate massive sets of UI class names automatically.
  • We parsed delimited strings (emails and URLs) by combining template literals with the infer keyword.

In Episode 48: String Manipulation Utilities, we will explore the built-in intrinsic utilities (like Uppercase and Capitalize) designed specifically to manipulate these template literal types!

typescript - This article is part of a series.
Part 47: This Article