Create types from string templates (TypeScript 4.1+).
Basic Template Literals
type Greeting = `Hello, ${string}`;
// "Hello, " + any string
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">;
// "onClick"
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiEndpoint = `/${string}`;
type ApiRoute = `${HttpMethod} ${ApiEndpoint}`;
type Route = "GET /users" | "POST /users" | "GET /posts";
String Manipulation Types
Uppercase, Lowercase, Capitalize, Uncapitalize
type Uppercase<S extends string> = intrinsic;
type Lowercase<S extends string> = intrinsic;
type Capitalize<S extends string> = intrinsic;
type Uncapitalize<S extends string> = intrinsic;
type T0 = Uppercase<"hello">; // "HELLO"
type T1 = Lowercase<"WORLD">; // "world"
type T2 = Capitalize<"hello">; // "Hello"
type T3 = Uncapitalize<"Hello">; // "hello"
Pattern Matching
type ExtractRoute<T extends string> = T extends `${infer Method} ${infer Path}`
? { method: Method; path: Path }
: never;
type Route = ExtractRoute<"GET /users">;
// { method: "GET"; path: "/users" }
Extract Parts
type ExtractMethod<T extends string> = T extends `${infer M} ${string}`
? M
: never;
type ExtractPath<T extends string> = T extends `${string} ${infer P}`
? P
: never;
type Method = ExtractMethod<"GET /users">; // "GET"
type Path = ExtractPath<"GET /users">; // "/users"
CSS Class Names
type Color = "red" | "blue" | "green";
type Size = "small" | "medium" | "large";
type ButtonClass = `btn-${Color}-${Size}`;
type Classes =
| "btn-red-small"
| "btn-red-medium"
| "btn-red-large"
| "btn-blue-small"
| // ... etc
API Route Types
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
type Resource = "users" | "posts" | "comments";
type IdParam = `${Resource}/${string}`;
type ApiRoute = `${HttpMethod} /api/${IdParam}`;
type Routes =
| "GET /api/users/123"
| "POST /api/posts"
| "PUT /api/comments/456";
Path Parsing
type Split<S extends string, D extends string> = S extends `${infer Head}${D}${infer Tail}`
? [Head, ...Split<Tail, D>]
: [S];
type PathParts = Split<"a/b/c", "/">;
// ["a", "b", "c"]
Exercises
Exercise 1: Event Handlers
// Create a type for event handler names:
// - Prefix: "on"
// - Event: "click" | "hover" | "focus"
// - Result: "onClick" | "onHover" | "onFocus"
Exercise 2: CSS Classes
// Create a type for button classes:
// - Base: "btn"
// - Variant: "primary" | "secondary"
// - Size: "sm" | "md" | "lg"
// - Result: "btn-primary-sm" | "btn-primary-md" | etc.
Exercise 3: API Routes
// Create a type for API routes:
// - Method: "GET" | "POST"
// - Resource: "users" | "posts"
// - Result: "GET /api/users" | "POST /api/posts" | etc.
Exercise 4: Path Extraction
// Create a type that extracts:
// - The last segment from a path
// - Example: "a/b/c" => "c"
Exercise 5: String Replacement
// Create a type that replaces:
// - All occurrences of a substring
// - Example: Replace<"hello-world", "-", "_"> => "hello_world"
Best Practices
- Use for string patterns - When you have known string formats
- Combine with unions - Create type-safe string literals
- Extract with infer - Parse strings into structured types
- Use built-in utilities - Capitalize, Uppercase, etc.
- Test with real values - Ensure types work as expected
Common Mistakes
- Not using extends string
// ❌ Wrong
type Bad<T> = `Hello, ${T}`;
// ✅ Correct
type Good<T extends string> = `Hello, ${T}`;
- Complex template literals
// ❌ Too complex, might hit limits
type VeryComplex = `${A}${B}${C}${D}${E}${F}...`;
// ✅ Keep it simple
type Simple = `${A}-${B}`;
- Not handling edge cases
// ❌ Might not handle empty strings
type Bad<T extends string> = `prefix-${T}`;
// ✅ Consider edge cases
type Good<T extends string> = T extends "" ? "prefix" : `prefix-${T}`;
Next Steps
Learn about Recursive Types.