In JavaScript, template literals are a way to create strings that can include expressions. In TypeScript, Template Literal Types are a type - level equivalent of JavaScript template literals. They allow you to define string - literal types by interpolating other string - literal types.
Here is a basic example:
type Greeting = `Hello, ${string}`;
let message: Greeting = "Hello, John"; // This is valid
// let invalidMessage: Greeting = "Hi, John"; // This will cause a type error
In this example, the Greeting
type is defined as a string that starts with "Hello, "
followed by any string.
Template Literal Types support type interpolation, where you can insert types into a template string. You can use other string - literal types, union types, or even generic types within the template.
type Color = "red" | "blue" | "green";
type HexColor = `#${Color}`;
let redHex: HexColor = "#red"; // Valid
let invalidHex: HexColor = "#yellow"; // Type error
In this case, the HexColor
type is a union of string - literal types that start with #
followed by one of the colors in the Color
union type.
Template Literal Types can be used in combination with generics to create flexible type definitions.
type Prefix<T extends string> = `prefix-${T}`;
type Result1 = Prefix<"abc">; // "prefix-abc"
type Result2 = Prefix<"123">; // "prefix-123"
Here, the Prefix
generic type takes a string - literal type T
and creates a new string - literal type with the prefix "prefix-"
.
You can also use Template Literal Types within conditional types to perform type transformations based on certain conditions.
type IsSuccess<T extends string> = T extends `success-${string}`? true : false;
type Check1 = IsSuccess<"success-data">; // true
type Check2 = IsSuccess<"error-data">; // false
In this example, the IsSuccess
conditional type checks if a string - literal type starts with "success-"
and returns true
or false
accordingly.
Template Literal Types can be used to generate event names in a type - safe way.
type EventType = "click" | "hover" | "focus";
type EventName<T extends EventType> = `${T}-event`;
function handleEvent(eventName: EventName<EventType>) {
console.log(`Handling ${eventName}`);
}
handleEvent("click-event"); // Valid
// handleEvent("custom-event"); // Type error
This ensures that only valid event names can be passed to the handleEvent
function.
When working with APIs, you can use Template Literal Types to generate API endpoints.
type ApiVersion = "v1" | "v2";
type Endpoint<T extends ApiVersion> = `/${T}/users`;
function fetchData(endpoint: Endpoint<ApiVersion>) {
// Fetch data from the endpoint
console.log(`Fetching data from ${endpoint}`);
}
fetchData("/v1/users"); // Valid
// fetchData("/v3/users"); // Type error
While Template Literal Types can be very powerful, it’s important to keep your type definitions readable. Avoid creating overly complex template literals that are hard to understand.
When using union types in Template Literal Types, make sure the union is well - defined. Too many options in a union can make the type system more difficult to manage.
Conditional types can be combined with Template Literal Types to perform more advanced type transformations. Use them to create more intelligent type definitions.
TypeScript Template Literal Types are a powerful feature that allows you to create more precise and expressive type definitions. They enable type - safe string manipulation at the type level, which can significantly improve the reliability and maintainability of your TypeScript code. By understanding the fundamental concepts, usage methods, common practices, and best practices, you can effectively leverage Template Literal Types in your projects.