✅ — unions are one of the most powerful and expressive features of TypeScript. They let you describe data that can take on multiple possible forms, making your code safer and clearer.
Here’s a comprehensive, unique explanation with practical examples across different domains.
In JavaScript, a variable can hold any type at runtime. TypeScript makes this safer by introducing union types, which let you explicitly say:
👉 “This value can be either A or B or C.”
1. What is a Union Type?
A union type combines multiple possible types using the | (pipe) operator.
let value: string | number;
value = "Hello"; // ✅
value = 42; // ✅
value = true; // ❌ Error: not string or number
Here, value can be string OR number — but nothing else.
2. Unions with Primitive Types
You can restrict variables to specific primitives.
type Status = "loading" | "success" | "error";
let s: Status;
s = "loading"; // ✅
s = "done"; // ❌ Error
👉 This pattern is called a string literal union and is often used instead of enums.
3. Unions with Objects
Union types are not limited to primitives.
You can describe alternative object shapes:
type Dog = { kind: "dog"; bark: () => void };
type Cat = { kind: "cat"; meow: () => void };
type Pet = Dog | Cat;
function interact(pet: Pet) {
if (pet.kind === "dog") {
pet.bark(); // ✅ Safe
} else {
pet.meow(); // ✅ Safe
}
}
👉 This is called a discriminated union — each object has a distinguishing field (kind).
4. Functions with Union Parameters
Union types are very useful for function arguments:
function format(input: string | number): string {
return typeof input === "number" ? input.toFixed(2) : input.toUpperCase();
}
console.log(format(42)); // "42.00"
console.log(format("hello")); // "HELLO"
5. Union with Arrays
Unions apply to arrays too:
let arr: (string | number)[] = ["a", 1, "b", 2];
arr.push("c"); // ✅
arr.push(true); // ❌
6. Narrowing Union Types
Since unions can be broad, TypeScript requires type narrowing before using specific methods.
Ways to narrow:
typeofcheckfunction print(x: string | number) { if (typeof x === "string") { console.log(x.toUpperCase()); } else { console.log(x.toFixed(2)); } }inoperatortype Car = { drive: () => void }; type Boat = { sail: () => void }; type Vehicle = Car | Boat; function move(v: Vehicle) { if ("drive" in v) v.drive(); else v.sail(); }- Discriminated property
type Success = { status: "success"; data: string }; type Error = { status: "error"; message: string }; type Result = Success | Error; function handle(res: Result) { if (res.status === "success") { console.log("Data:", res.data); } else { console.error("Error:", res.message); } }
7. Real-World Examples
(a) API Response Handling
type ApiResponse<T> =
| { status: "ok"; data: T }
| { status: "error"; error: string };
async function fetchUser(): Promise<ApiResponse<{ id: number; name: string }>> {
return { status: "ok", data: { id: 1, name: "Alice" } };
}
(b) React Component Props with Unions
type ButtonProps =
| { variant: "text"; label: string }
| { variant: "icon"; icon: string };
const Button = (props: ButtonProps) => {
if (props.variant === "text") {
return <button>{props.label}</button>;
}
return <button><i className={props.icon}></i></button>;
};
👉 This ensures only valid props combinations are allowed.
(c) Angular Input Model
type InputType = "text" | "email" | "password";
@Component({...})
export class InputComponent {
@Input() type: InputType = "text";
}
(d) Vue Component with Props
type Size = "small" | "medium" | "large";
export default defineComponent({
props: {
size: { type: String as PropType<Size>, required: true }
}
});
8. Union vs Intersection
- Union (
|) → value can be either A or B. - Intersection (
&) → value must be A AND B at the same time.
type A = { a: number };
type B = { b: number };
type U = A | B; // either {a} or {b}
type I = A & B; // must have both {a, b}
9. Best Practices for Unions
- ✅ Use string literal unions instead of enums for lightweight status codes.
- ✅ Use discriminated unions for safe object modeling.
- ✅ Always narrow types before accessing union-specific fields.
- ❌ Don’t create unions that are too large (hard to narrow).
- ❌ Don’t use
anywhen a union type can give better safety.
10. Conclusion
Unions in TypeScript:
- Allow variables to hold multiple possible types.
- Work with primitives, objects, arrays, and functions.
- Require type narrowing for safe access.
- Are crucial in API response handling, UI props, and real-world domain modeling.
👉 Mastering unions helps you write expressive, type-safe, and bug-resistant TypeScript code.