Union Syntax
Union Syntax
Union types allow a value to be one of several types, using the | operator.
Basic Union
// A value can be string OR number
let id: string | number;
id = "abc123"; // OK
id = 123; // OK
// id = true; // Error!
Union with Literals
type Direction = "up" | "down" | "left" | "right";
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
function move(direction: Direction): void {
console.log(`Moving ${direction}`);
}
move("up"); // OK
// move("forward"); // Error!
Union of Object Types
type Success = {
status: "success";
data: string[];
};
type Error = {
status: "error";
message: string;
};
type Result = Success | Error;
function handleResult(result: Result) {
if (result.status === "success") {
console.log(result.data); // OK
} else {
console.log(result.message); // OK
}
}
Function Parameters
function format(input: string | number): string {
if (typeof input === "string") {
return input.toUpperCase();
} else {
return input.toFixed(2);
}
}
Type Narrowing
Type Narrowing
Type narrowing is the process of refining a union type to a more specific type using type guards.
typeof Guards
function process(value: string | number | boolean) {
if (typeof value === "string") {
// TypeScript knows value is string
return value.toUpperCase();
} else if (typeof value === "number") {
// TypeScript knows value is number
return value.toFixed(2);
} else {
// TypeScript knows value is boolean
return value ? "yes" : "no";
}
}
instanceof Guards
class Dog {
bark() { return "Woof!"; }
}
class Cat {
meow() { return "Meow!"; }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
return animal.bark();
} else {
return animal.meow();
}
}
Truthiness Guards
function printName(name: string | null) {
if (name) {
// TypeScript knows name is string
console.log(name.toUpperCase());
}
}
'in' Operator
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim();
} else {
animal.fly();
}
}
Discriminated Unions
Discriminated Unions
Discriminated unions use a common property (discriminant) to distinguish between types.
Basic Pattern
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rectangle"; width: number; height: number }
| { kind: "triangle"; base: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
case "triangle":
return (shape.base * shape.height) / 2;
}
}
Exhaustive Checking
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
case "triangle":
return (shape.base * shape.height) / 2;
default:
const _exhaustive: never = shape;
return _exhaustive;
}
}
Real-World Example
type Action =
| { type: "INCREMENT"; amount: number }
| { type: "DECREMENT"; amount: number }
| { type: "RESET" };
function reducer(state: number, action: Action): number {
switch (action.type) {
case "INCREMENT":
return state + action.amount;
case "DECREMENT":
return state - action.amount;
case "RESET":
return 0;
}
}
Practice Problems
Create a reusable React component implementing Union Types. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Union Types using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Union Types for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What operator creates a union type?
2. What is a discriminated union?
3. What is type narrowing?
4. What does exhaustive checking ensure?
Flashcards
Question
How do you create a union type?
Click to reveal answer
Answer
Use the pipe operator: string | number
Question
What is a type guard?
Click to reveal answer
Answer
An expression that checks the type at runtime
Question
What is a discriminated union?
Click to reveal answer
Answer
A union with a common literal property for discrimination
Question
What is the never type used for in discriminated unions?
Click to reveal answer
Answer
Exhaustive checking to ensure all cases are handled
Question
What is Union Types?
Click to reveal answer
Answer
Union Types is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Union types allow a value to be one of several types
- 2.Type guards narrow types using typeof, instanceof, or in
- 3.Discriminated unions use a common property to distinguish types
- 4.Exhaustive checking ensures all union cases are handled
- 5.Union types are powerful for modeling state
Interview Tips
- •Explain discriminated unions and their benefits
- •Show how type narrowing works with typeof and instanceof
- •Discuss exhaustive checking with the never type
Cheat Sheet
Cheat Sheet
Union Syntax
type ID = string | number;
type Status = "active" | "inactive";
Type Guards
if (typeof x === "string") { }
if (x instanceof Error) { }
if ("prop" in x) { }
Discriminated Unions
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rect"; w: number; h: number };
switch (shape.kind) {
case "circle": // ...
case "rect": // ...
}
Exhaustive Check
default:
const _: never = shape;
return _;