Template Literal Types, introduced in TypeScript 4.1, bring the power of JavaScript template literals to the type system. They allow you to create complex string-based types by combining literal types, string literals, and type inference.
Template Literal Types use the backtick (`) syntax, similar to template literals in JavaScript. They can include placeholders for types, denoted by ${Type}.
type Greeting = `Hello, ${string}!`;
let myGreeting: Greeting = "Hello, TypeScript!"; // Valid
let invalidGreeting: Greeting = "Hi there!"; // Error
Template Literal Types excel at generating union types based on string combinations:
type Color = "red" | "blue" | "green";
type Size = "small" | "medium" | "large";
type Product = `${Size}-${Color}`;
// Resulting type: "small-red" | "small-blue" | "small-green" | "medium-red" | ...
They're particularly useful for creating type-safe event handler names:
type EventName = "click" | "focus" | "blur";
type Handler = `on${Capitalize}`;
// Resulting type: "onClick" | "onFocus" | "onBlur"
TypeScript can infer types within template literals, enabling powerful pattern matching:
type ExtractProp = T extends `get${infer R}` ? R : never;
type Prop = ExtractProp<"getName">; // Inferred as "Name"
Template Literal Types work seamlessly with Mapped Types, allowing for complex type transformations:
type Getters = {
[K in keyof T as `get${Capitalize}`]: () => T[K]
};
interface Person {
name: string;
age: number;
}
type PersonGetters = Getters;
// Resulting type: { getName: () => string; getAge: () => number }
While powerful, Template Literal Types can become complex. It's important to balance type safety with readability. For intricate type manipulations, consider breaking down the logic into smaller, reusable type aliases.
Template Literal Types shine in scenarios where you need to work with string-based APIs or create precise string union types. They're particularly valuable in libraries and frameworks for providing type-safe interfaces.
Template Literal Types represent a significant enhancement to TypeScript's type system. They enable developers to create more expressive and precise types, especially when working with string-based operations. By mastering this feature, you can write more robust and self-documenting code in TypeScript.