JavaScript > TypeScript > Advanced TypeScript > Union and intersection types
Union and Intersection Types in TypeScript
This example demonstrates how to use union and intersection types in TypeScript to create flexible and expressive type definitions. Learn how to combine types and define objects with specific properties.
Understanding Union Types
Union types
allow a variable to hold values of different types. In the example, StringOrNumber
can be either a string
or a number
. When working with union types, you often need to narrow down the type using type guards (like typeof
) to safely perform operations specific to that type.
type StringOrNumber = string | number;
let value: StringOrNumber;
value = 'Hello'; // Valid
value = 123; // Valid
// value = true; // Error: Type 'boolean' is not assignable to type 'StringOrNumber'.
function processValue(input: StringOrNumber): void {
if (typeof input === 'string') {
console.log('String:', input.toUpperCase());
} else {
console.log('Number:', input * 2);
}
}
Concepts Behind the Snippet
Union types represent a value that can be one of several types. They are defined using the pipe operator (|
). TypeScript uses structural typing, meaning type compatibility is based on the shape of the object, not its name. Type guards are crucial for safely interacting with union types.
Understanding Intersection Types
Intersection types
combine multiple types into one. The resulting type has all the properties of the intersected types. In the example, ColorfulCircle
has both the color
property from Colorful
and the radius
property from Circle
.
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
type ColorfulCircle = Colorful & Circle;
const colorfulCircle: ColorfulCircle = {
color: 'red',
radius: 10,
};
console.log(colorfulCircle.color);
console.log(colorfulCircle.radius);
Concepts Behind the Snippet
Intersection types create a new type that combines the properties of existing types. They are defined using the ampersand operator (&
). The resulting type has all the properties and methods of all the intersected types. If there are conflicting property types, TypeScript attempts to resolve them or reports an error if it cannot.
Real-Life Use Case: Configuration Objects
Intersection types are useful for combining configuration interfaces. In this example, we combine AppConfig
and FeatureFlags
into a FullConfig
type. This ensures that the configuration object has all the necessary properties.
interface AppConfig {
apiEndpoint: string;
timeout: number;
}
interface FeatureFlags {
enableDarkMode: boolean;
enableAnalytics: boolean;
}
type FullConfig = AppConfig & FeatureFlags;
const config: FullConfig = {
apiEndpoint: 'https://api.example.com',
timeout: 5000,
enableDarkMode: true,
enableAnalytics: false,
};
console.log(config.apiEndpoint);
console.log(config.enableDarkMode);
Real-Life Use Case: Event Handlers
Union types are often used in event handling scenarios where an event can be one of several types (e.g., MouseEvent
or KeyboardEvent
). The function handleEvent
uses a type guard ('key' in event
) to determine which type of event it is dealing with and access the appropriate properties.
interface MouseEvent {
x: number;
y: number;
}
interface KeyboardEvent {
key: string;
}
type UIEvent = MouseEvent | KeyboardEvent;
function handleEvent(event: UIEvent) {
if ('key' in event) {
console.log('Keyboard event:', event.key);
} else {
console.log('Mouse event:', event.x, event.y);
}
}
Best Practices
Interview Tip
Be prepared to explain the difference between union and intersection types, and provide examples of when you would use each. Understand the importance of type guards when working with union types. Explain that Union types use |
and Intersection types use &
.
When to Use Them
Alternatives
Pros
Cons
FAQ
-
What is the difference between a union and an intersection type?
A union type (A | B
) represents a value that can be either type A or type B. An intersection type (A & B
) represents a value that has both the properties of type A and type B. -
When should I use a union type?
Use a union type when a variable or function parameter can accept values of different types. For example, a function that can accept either a string or a number. -
When should I use an intersection type?
Use an intersection type when you want to combine multiple types into a single type with all the properties of the combined types. For example, combining multiple configuration interfaces. -
What are type guards and why are they important?
Type guards are expressions that narrow down the type of a variable within a specific scope. They are important when working with union types to ensure that you are only accessing properties that are valid for the current type. Common type guards includetypeof
,instanceof
, and custom type guard functions.