String literal types in TypeScript allow you to specify exact, predefined string values that a variable can hold. This feature enables you to create safer and more predictable code by restricting variables to specific values, such as command names, statuses, or options. In this tutorial, we’ll cover the basics of string literal types, walk through detailed examples, and show you how to use them in real-world scenarios.
TypeScript’s string literal types allow you to define variables that can only hold specific string values. This feature provides a form of type safety, reducing the risk of errors and helping TypeScript catch potential issues at compile time. String literal types are particularly useful for defining commands, statuses, and configurations where only a limited set of values are valid.
A string literal type is a type in TypeScript that limits a variable to specific string values. Instead of allowing any string, you can define exact values that the variable can hold, which TypeScript will enforce.
let status: "success" | "error" | "loading";
status = "success"; // Valid
status = "error"; // Valid
// status = "failed"; // Error: Type '"failed"' is not assignable to type '"success" | "error" | "loading"'
In this example:
status
variable is defined with a string literal type, allowing only "success"
, "error"
, or "loading"
.String literal types can be used in variables, function parameters, and return types. They’re useful for making your code clearer and safer by restricting values to an exact set.
To declare a string literal type, list the allowed values separated by the |
symbol.
type Direction = "up" | "down" | "left" | "right";
let move: Direction;
move = "up"; // Valid
move = "left"; // Valid
// move = "forward"; // Error: Type '"forward"' is not assignable to type 'Direction'
In this example:
Direction
is a type that only accepts "up"
, "down"
, "left"
, or "right"
.You can define a type alias to reuse string literal types across multiple variables or parameters.
type Status = "pending" | "completed" | "failed";
let taskStatus: Status = "pending"; // Valid
// taskStatus = "in-progress"; // Error: Type '"in-progress"' is not assignable to type 'Status'
Using a type alias makes your code more readable and reusable, especially when using the same set of values across different parts of your code.
String literal types are particularly useful in functions, allowing you to define parameters that accept only specific values.
Let’s create a function that accepts specific string commands for controlling a media player.
type MediaCommand = "play" | "pause" | "stop";
function controlMedia(command: MediaCommand): void {
if (command === "play") {
console.log("Playing media");
} else if (command === "pause") {
console.log("Pausing media");
} else {
console.log("Stopping media");
}
}
controlMedia("play"); // Output: Playing media
controlMedia("pause"); // Output: Pausing media
// controlMedia("fast-forward"); // Error: Argument of type '"fast-forward"' is not assignable to parameter of type 'MediaCommand'
In this example:
controlMedia
function accepts only "play"
, "pause"
, or "stop"
as valid commands.You can also use string literal types in return types to indicate exactly what a function might return.
function getConnectionStatus(): "connected" | "disconnected" | "reconnecting" {
// Example implementation
return "connected";
}
let status = getConnectionStatus(); // Type is "connected" | "disconnected" | "reconnecting"
This example ensures that getConnectionStatus
only returns one of the specified values, making it easier to manage and check the possible outcomes.
String literal types work well with union types, allowing you to combine multiple types in a single variable or parameter.
Let’s say you want a variable that can be either a number or specific string values. You can use a union type with string literals to achieve this.
type Result = "success" | "failure" | number;
let response: Result;
response = "success"; // Valid
response = 404; // Valid
// response = "error"; // Error: Type '"error"' is not assignable to type 'Result'
In this example:
Result
can hold "success"
, "failure"
, or any number.When working with APIs, you may handle different response statuses using string literal types, ensuring only expected statuses are processed.
type ApiResponseStatus = "ok" | "error" | "loading";
function handleApiResponse(status: ApiResponseStatus): void {
switch (status) {
case "ok":
console.log("Request successful!");
break;
case "error":
console.error("An error occurred.");
break;
case "loading":
console.log("Loading data...");
break;
}
}
handleApiResponse("ok"); // Output: Request successful!
handleApiResponse("loading"); // Output: Loading data...
// handleApiResponse("timeout"); // Error: Argument of type '"timeout"' is not assignable to parameter of type 'ApiResponseStatus'
In this example:
ApiResponseStatus
type ensures that only valid status values are processed.String literal types can help with settings or configuration options, like defining themes in an application.
type Theme = "light" | "dark" | "system";
function setTheme(theme: Theme): void {
console.log(`Theme set to: ${theme}`);
}
setTheme("dark"); // Output: Theme set to: dark
setTheme("system"); // Output: Theme set to: system
// setTheme("blue"); // Error: Argument of type '"blue"' is not assignable to parameter of type 'Theme'
Here:
Theme
limits the theme settings to "light"
, "dark"
, or "system"
.Both string literal types and enum types allow you to define a set of specific values. However, they serve different purposes and offer distinct advantages.
String literal types in TypeScript allow you to specify exact values for variables, enhancing type safety and reducing errors. They are especially useful for handling specific commands, statuses, or configuration options where only certain values are allowed. By using string literal types in your TypeScript projects, you can make your code more readable, robust, and easier to maintain. With this guide, you should now have a clear understanding of how to define, use, and apply string literal types in real-world scenarios.