TypeScript Union Types
Allow multiple type possibilities
🔗 What are Union Types?
Union types allow a variable to hold values of multiple types using the pipe (|) operator. They provide flexibility while maintaining type safety, letting you specify that a value can be one of several types.
// Simple union type
let id: string | number;
id = "abc123"; // Valid
id = 456; // Also valid
Union Type Patterns
Primitive Unions
Combine basic types
type ID =
string | number;
type Value =
string | boolean;
Literal Unions
Specific value options
type Status =
"active" |
"inactive" |
"pending";
Object Unions
Different object shapes
type Response =
Success | Error;
type Success = {
data: string;
};
Type Guards
Check union types
if (typeof x
=== "string") {
// x is string
}
🔹 Basic Union Types
Combine primitive types:
let value: string | number;
value = "Hello";
console.log(`String value: ${value}`);
value = 42;
console.log(`Number value: ${value}`);
// value = true; // Error: boolean not in union
Output:
String value: Hello
Number value: 42
🔹 Union Type in Functions
Function parameters can accept multiple types:
function printId(id: string | number) {
console.log(`Your ID is: ${id}`);
}
printId(101);
printId("ABC123");
function formatValue(value: string | number | boolean) {
return `Value: ${value}`;
}
console.log(formatValue("text"));
console.log(formatValue(123));
console.log(formatValue(true));
Output:
Your ID is: 101
Your ID is: ABC123
Value: text
Value: 123
Value: true
🔹 Type Guards
Check which type you're working with:
function processValue(value: string | number) {
if (typeof value === "string") {
console.log(`String length: ${value.length}`);
} else {
console.log(`Number doubled: ${value * 2}`);
}
}
processValue("Hello");
processValue(10);
Output:
String length: 5
Number doubled: 20
🔹 Literal Union Types
Restrict to specific values:
type Direction = "north" | "south" | "east" | "west";
type Status = "success" | "error" | "loading";
let heading: Direction = "north";
let requestStatus: Status = "loading";
function move(direction: Direction) {
console.log(`Moving ${direction}`);
}
move("north");
move("east");
// move("up"); // Error: "up" not in union
Output:
Moving north
Moving east
🔹 Union of Object Types
Combine different object structures:
type Success = {
status: "success";
data: string;
};
type Error = {
status: "error";
message: string;
};
type Response = Success | Error;
function handleResponse(response: Response) {
if (response.status === "success") {
console.log(`Data: ${response.data}`);
} else {
console.log(`Error: ${response.message}`);
}
}
handleResponse({ status: "success", data: "User created" });
handleResponse({ status: "error", message: "Not found" });
Output:
Data: User created
Error: Not found
🔹 Array Union Types
Arrays with multiple value types:
let mixedArray: (string | number)[] = [1, "two", 3, "four"];
mixedArray.forEach(item => {
console.log(`Item: ${item}, Type: ${typeof item}`);
});
type StringOrNumberArray = string[] | number[];
let stringArray: StringOrNumberArray = ["a", "b", "c"];
let numberArray: StringOrNumberArray = [1, 2, 3];
Output:
Item: 1, Type: number
Item: two, Type: string
Item: 3, Type: number
Item: four, Type: string
🔹 Discriminated Unions
Use a common property to distinguish types:
type Circle = {
kind: "circle";
radius: number;
};
type Square = {
kind: "square";
sideLength: number;
};
type Shape = Circle | Square;
function getArea(shape: Shape): number {
if (shape.kind === "circle") {
return Math.PI * shape.radius ** 2;
} else {
return shape.sideLength ** 2;
}
}
console.log(`Circle area: ${getArea({ kind: "circle", radius: 5 }).toFixed(2)}`);
console.log(`Square area: ${getArea({ kind: "square", sideLength: 4 })}`);
Output:
Circle area: 78.54
Square area: 16
🔹 Practical Example
Building a flexible API response handler:
type LoadingState = {
status: "loading";
};
type SuccessState = {
status: "success";
data: { id: number; name: string }[];
};
type ErrorState = {
status: "error";
error: string;
};
type ApiState = LoadingState | SuccessState | ErrorState;
function displayState(state: ApiState) {
switch (state.status) {
case "loading":
console.log("Loading...");
break;
case "success":
console.log(`Loaded ${state.data.length} items`);
break;
case "error":
console.log(`Error: ${state.error}`);
break;
}
}
displayState({ status: "loading" });
displayState({ status: "success", data: [{ id: 1, name: "Item" }] });
displayState({ status: "error", error: "Network failed" });
Output:
Loading...
Loaded 1 items
Error: Network failed