In TypeScript, literal types are types that allow you to define variables with specific, predefined values instead of broad types like string
or number
.
The main reason is to give us greater control and safety over the values that a variable can take, limiting the available options.
String Literal Types
String literal types allow you to define a variable that can only have one of several specific string values.
type Direction = "north" | "south" | "east" | "west";
let direction: Direction;
direction = "north"; // Correct
direction = "south"; // Correct
// direction = "northeast"; // Error: Type '"northeast"' is not assignable to type 'Direction'.
Numeric Literal Types
Similar to string literals, numeric literal types allow a variable to only have certain specific numeric values.
type OneToTen = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
let number: OneToTen;
number = 1; // Correct
number = 5; // Correct
// number = 11; // Error: Type '11' is not assignable to type 'OneToTen'.
Literals and Union Types
Literal types are often used together with union types to create variables that can accept several specific values.
type Answer = "yes" | "no" | "maybe";
function respond(answer: Answer): void {
console.log(`The answer is: ${answer}`);
}
respond("yes"); // Correct
respond("no"); // Correct
respond("maybe"); // Correct
// respond("perhaps"); // Error: Type '"perhaps"' is not assignable to type 'Answer'.
Literals and Custom Types
Literal types can also be used in the definition of more complex custom types, providing greater control over the values of object properties.
type Status = "started" | "in progress" | "completed";
interface Task {
title: string;
description: string;
status: Status;
}
let task: Task = {
title: "Learn TypeScript",
description: "Study literal types in TypeScript.",
status: "in progress"
};
// task.status = "pending"; // Error: Type '"pending"' is not assignable to type 'Status'.
Template Literals
TypeScript supports template literals to create string literal types from combinations of other literal types.
type Prefix = "Mr." | "Mrs." | "Ms.";
type FullName = `${Prefix} ${string}`;
let person1: FullName = "Mr. John Doe";
let person2: FullName = "Mrs. Jane Smith";
// let person3: FullName = "Doctor John Doe"; // Error: Type '"Doctor John Doe"' is not assignable to type 'FullName'.
Using Constant Literals
When appropriate, use constant literals to define specific values that should not change.
const ACTIVE_STATUS = "active";
const INACTIVE_STATUS = "inactive";
type Status = typeof ACTIVE_STATUS | typeof INACTIVE_STATUS;
let userStatus: Status = ACTIVE_STATUS;
Practical Examples
Parameter Validation with Literal Types
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
function makeRequest(url: string, method: HttpMethod): void {
console.log(`Making request to ${url} with method ${method}`);
}
makeRequest("https://api.example.com", "GET"); // Correct
makeRequest("https://api.example.com", "POST"); // Correct
// makeRequest("https://api.example.com", "PATCH"); // Error: Type '"PATCH"' is not assignable to type 'HttpMethod'.
Setting Options with Literals
type Mode = "dark" | "light";
interface Settings {
theme: Mode;
notifications: boolean;
}
let config: Settings = {
theme: "dark",
notifications: true
};
function changeTheme(config: Settings, newTheme: Mode): Settings {
config.theme = newTheme;
return config;
}
config = changeTheme(config, "light"); // Correct
// config = changeTheme(config, "auto"); // Error: Type '"auto"' is not assignable to type 'Mode'.