TypeScript - Literal Types: A Beginner's Guide
Hello, future coding superstar! Today, we're diving into the exciting world of TypeScript Literal Types. Don't worry if you're new to programming – I'll be your friendly guide through this adventure. By the end of this tutorial, you'll be wielding literal types like a pro!
What are Literal Types?
Before we jump in, let's imagine you're ordering a pizza. You can't just say, "I want a pizza." You need to specify the size: small, medium, or large. In TypeScript, literal types are like those specific pizza sizes – they're exact values that a variable can have.
Syntax
The syntax for literal types is straightforward. You simply use the exact value you want to allow. Let's look at a basic example:
let pizzaSize: "small" | "medium" | "large";
In this case, pizzaSize
can only be "small", "medium", or "large". Nothing else is allowed – not even "extra large" or "tiny"!
String Literal Types
String literal types are the most common and easiest to understand. They're exactly what they sound like – specific strings that a variable can be.
Example 1: Days of the Week
type DayOfWeek = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";
let today: DayOfWeek = "Monday";
today = "Friday"; // This is fine
today = "Someday"; // Error! Type '"Someday"' is not assignable to type 'DayOfWeek'.
In this example, DayOfWeek
is a type that can only be one of the seven days of the week. Try to assign any other string, and TypeScript will wag its finger at you!
Example 2: Traffic Light Colors
type TrafficLightColor = "Red" | "Yellow" | "Green";
function changeLight(color: TrafficLightColor) {
console.log(`The light has changed to ${color}`);
}
changeLight("Green"); // Works fine
changeLight("Purple"); // Error! Argument of type '"Purple"' is not assignable to parameter of type 'TrafficLightColor'.
Here, we're ensuring that our traffic light can only change to valid colors. No disco lights allowed on this street!
Numeric Literal Types
Just like with strings, we can create literal types with numbers. This is great for when you want to restrict a value to specific numbers.
Example 3: Dice Rolls
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
function rollDice(): DiceRoll {
return Math.floor(Math.random() * 6) + 1 as DiceRoll;
}
let myRoll = rollDice();
console.log(`You rolled a ${myRoll}`);
In this example, we're making sure that our dice can only roll numbers from 1 to 6. No loaded dice in our game!
Example 4: Shirt Sizes
type ShirtSize = 36 | 38 | 40 | 42 | 44;
let myShirtSize: ShirtSize = 40;
myShirtSize = 41; // Error! Type '41' is not assignable to type 'ShirtSize'.
Here, we're restricting shirt sizes to specific numbers. No in-between sizes allowed in this store!
Combined Literal Types
The real power of literal types shines when we combine different types of literals.
Example 5: Game Character Status
type CharacterStatus = "Alive" | "Dead" | 1 | 0;
let hero: CharacterStatus = "Alive";
hero = 1; // This is also valid
hero = "Wounded"; // Error! Type '"Wounded"' is not assignable to type 'CharacterStatus'.
In this game, a character can be "Alive", "Dead", 1 (representing alive), or 0 (representing dead). It's like having both a text and a code representation!
Use Cases for Literal Types
Literal types are incredibly useful in many scenarios. Let's explore a few:
1. Function Parameters
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
function sendRequest(url: string, method: HttpMethod) {
// Send the request
console.log(`Sending ${method} request to ${url}`);
}
sendRequest("https://api.example.com", "GET"); // Works fine
sendRequest("https://api.example.com", "FETCH"); // Error! Argument of type '"FETCH"' is not assignable to parameter of type 'HttpMethod'.
By using a literal type for the HTTP method, we ensure that only valid methods can be used.
2. Configuration Objects
type Theme = "light" | "dark" | "system";
type Language = "en" | "es" | "fr" | "de";
interface AppConfig {
theme: Theme;
language: Language;
notifications: boolean;
}
const myConfig: AppConfig = {
theme: "dark",
language: "en",
notifications: true
};
Literal types help us create strict configuration objects, preventing typos and invalid settings.
3. State Machines
type LoginState = "loggedOut" | "loggingIn" | "loggedIn" | "error";
class LoginManager {
private state: LoginState = "loggedOut";
login() {
this.state = "loggingIn";
// Perform login logic
this.state = Math.random() > 0.5 ? "loggedIn" : "error";
}
logout() {
this.state = "loggedOut";
}
getState(): LoginState {
return this.state;
}
}
Here, we use literal types to represent different states in a login process, ensuring that the state can only be one of the predefined values.
Methods Table
Here's a table summarizing the key methods and concepts we've covered:
Method/Concept | Description | Example |
---|---|---|
Type Declaration | Defining a new type using literal values | type DayOfWeek = "Monday" \| "Tuesday" \| ... |
Variable Assignment | Assigning a literal type to a variable | let today: DayOfWeek = "Monday"; |
Function Parameters | Using literal types in function parameters | function sendRequest(method: HttpMethod) {...} |
Combined Literals | Mixing different types of literals | type Status = "Active" \| "Inactive" \| 0 \| 1; |
Interface Properties | Using literal types in interface properties | interface Config { theme: "light" \| "dark" } |
And there you have it, my coding apprentice! You've just leveled up in your TypeScript journey by mastering literal types. Remember, like choosing the perfect pizza topping, literal types help you be specific and avoid mistakes. Keep practicing, and soon you'll be creating type-safe code that's as delicious as a perfectly crafted pizza! ??
Credits: Image by storyset