In Part 1 we saw that const creates literal types.
If you write const role = "admin", for TypeScript role is not just a simple string, but specifically "admin".
Today we’re going to see how to use that to create bulletproof code.
String vs. String Literal
Imagine you have a function to paint a button.
function paintButton(color: string) {
if (color === 'rde') { // ❌ Oops, typo ("rde" instead of "red")
return '🔴';
}
return '🔵';
}
paintButton("blue"); // ✅ Good
paintButton("potato 🥔"); // ✅ Good (but it shouldn't be, potato is not a color!)function paintButton(color: string) {
if (color === 'rde') { // ❌ Oops, typo ("rde" instead of "red")
return '🔴';
}
return '🔵';
}
paintButton("blue"); // ✅ Good
paintButton("potato 🥔"); // ✅ Good (but it shouldn't be, potato is not a color!)The problem here is that string is too broad. It accepts “blue”, “red”, and also “potato 🥔” or “asdfg”.
Type Unions
This is where the | (pipe) operator comes in. It reads as “OR”.
We can tell TypeScript: “The color can only be ‘red’ OR ‘blue’ OR ‘green’”.
type ButtonColor = "red" | "blue" | "green";
function paintButton(color: ButtonColor) {
// ...
}
paintButton("red"); // ✅ Perfect
paintButton("green"); // ✅ Perfect
paintButton("potato 🥔");
// ❌ Error: Argument of type '"potato 🥔"' is not assignable to parameter of type 'ButtonColor'.type ButtonColor = "red" | "blue" | "green";
function paintButton(color: ButtonColor) {
// ...
}
paintButton("red"); // ✅ Perfect
paintButton("green"); // ✅ Perfect
paintButton("potato 🥔");
// ❌ Error: Argument of type '"potato 🥔"' is not assignable to parameter of type 'ButtonColor'.Boom! 💥 You just eliminated an entire category of bugs. No one can pass an incorrect string to your function anymore.
Autocomplete (IntelliSense)
The best part is not just the safety, it’s the developer experience.
Try it yourself: Place your cursor between the quotes and press Ctrl + Space in each one. In the first one there are no suggestions (it’s a generic string). In the second one the editor suggests the valid options.
You don’t have to go to the documentation to know what values it accepted. The type itself tells you what values it accepts.
Mixed Unions
You can mix types if you want (although use it wisely):
// An ID can be a number (database ID) or a string (UUID)
type ID = number | string;
function findUser(id: ID) {
console.log("Finding user with ID:", id);
}
findUser(123); // ✅
findUser("abc-123"); // ✅// An ID can be a number (database ID) or a string (UUID)
type ID = number | string;
function findUser(id: ID) {
console.log("Finding user with ID:", id);
}
findUser(123); // ✅
findUser("abc-123"); // ✅Summary
- Literal Types: Exact values (
"red",1). - Unions (
|): Combine types (A | Bmeans A or B). - Use it to avoid “Magic Strings” and get free autocomplete.
In the next part we’ll see how to Type Objects and Interfaces to stop passing anonymous objects without control through our application.