Ts Intersection Types
Intersection Types combine multiple types into a new type, which contains all members of the combined types.
This is similar to multiple inheritance in object-oriented programming, allowing a type to have the characteristics of multiple types.
* * *
* * *
## Why We Need Intersection Types
In development, a type often needs to have the characteristics of multiple types.
For example, an employee is both a Person and a Worker, and needs to have the attributes of both.
Intersection types allow us to combine multiple types into one to meet this need.
> **Concept Explanation:** Intersection types use the `&` symbol to connect multiple types, indicating that the new type contains the members of all types. This is similar to the concept of multiple inheritance.
* * *
## Basic Syntax
Use the `&` symbol to combine multiple types.
## Example
// Define Person type
// Contains name and age
interface Person {
name: string;
age: number;
}
// Define Worker type
// Contains company name and salary
interface Worker {
company: string;
salary: number;
}
// Use intersection type to merge two interfaces
// Employee type has all properties of both Person and Worker
type Employee = Person & Worker;
// Create an object with characteristics of both types
var employee: Employee ={
name:"Alice",
age:25,
company:"Google",
salary:100000
};
console.log("Employee: "+ JSON.stringify(employee));
**Output:**
Employee: {"name":"Alice","age":25,"company":"Google","salary":100000}
> **Explanation:** Intersection type `A & B` means the new type has all properties of both A and B, and neither can be missing.
* * *
## Intersection Types and Interface Inheritance
Intersection types can replace multiple inheritance of interfaces.
## Example
// Define type A
interface A {
a: string;
}
// Define type B
interface B {
b: number;
}
// Using interface inheritance for multiple interfaces
// Requires using extends to inherit multiple interfaces
interface AB extends A, B {
c:boolean;
}
// Using intersection type (more concise)
// Directly use the & symbol to combine types
type ABType = A & B &{ c:boolean};
// Both methods can create a type containing all properties
var obj: ABType ={ a:"hello", b:42, c:true};
console.log("Object: "+ JSON.stringify(obj));
**Output:**
Object: {"a":"hello","b":42,"c":true}
> **Comparison:** Intersection types are more concise than interface inheritance, especially when inheriting from multiple types and adding extra properties.
* * *
## Type Mixing (Mixin Pattern)
Using intersection types to implement the Mixin pattern allows dynamic combination of class functionalities.
## Example
// Define constructor type
// Accepts any arguments and returns an object
type Constructor =new(...args: any[])=>{};
// Mixin: Add timestamp functionality
// Returns a new class extending Base
function Timestamped(Base: T){
return class extends Base {
timestamp =Date.now();
};
}
// Mixin: Add serialization functionality
// Returns a new class extending Base, including the serialize method
function Serializable(Base: T){
return class extends Base {
serialize(){
return JSON.stringify(this);
}
};
}
// Base user class
class User {
name: string;
constructor(name: string){
this.name= name;
}
}
// Combine Mixins
// Create a user class with timestamp functionality
var TimestampedUser = Timestamped(User);
// Create a user class with serialization functionality
var SerializableUser = Serializable(User);
// Combine two Mixins
var FullUser = Serializable(Timestamped(User));
// Create instance and test
var user =new FullUser("Alice");
console.log("Timestamp: "+ user.timestamp);
console.log("Serialized: "+ user.serialize());
**Output:**
Timestamp: 17134...Serialized: {"name":"Alice","timestamp":17134...}
> **Mixin Pattern:** This is a powerful pattern that can add new functionalities to a class without modifying the original class.
* * *
## Intersection Types and Union Types
Special attention must be paid to precedence when combining intersection types and union types.
## Example
// Union type: can be string or number
type StringOrNumber = string | number;
// Intersection type: intersection of incompatible types
// string & number = never (no type is both string and number)
type Both = string & number;
// Define three types
type A ={ a: string };
type B ={ b: number };
type C ={ c:boolean};
// Combining union types and intersection types
// (A | B) & C will intersect each branch of the union type with C
type Combined =(A | B)& C;
// The actual result is: { a: string; c: boolean } | { b: number; c: boolean }
// That is, either A + C, or B + C
var obj: Combined ={ a:"hello", c:true};
console.log("Combined: "+ JSON.stringify(obj));
**Output:**
Combined: {"a":"hello","c":true}
> **Important:** Intersecting incompatible types results in the `never` type. For example, `string & number` is invalid.
* * *
## Practical Intersection Types
Intersection types are commonly used to create utility types to implement type transformations.
## Example
// Mapped type: Make all properties optional
// Iterate over all properties of T, add ? to make them optional
type Partial={?: T};
// Mapped type: Make all properties required
// Iterate over all properties of T, remove ? to make them required
type Required={-?: T};
// Mapped type: Make all properties readonly
// Iterate over all properties of T, add readonly
type Readonly={ readonly : T};
// Define configuration interface
interface Config {
host: string;
port: number;
}
// Use utility types
var partialConfig: Partial={ host:"localhost"};
var requiredConfig: Required={ host:"localhost", port:8080};
var readonlyConfig: Readonly={ host:"localhost", port:8080};
console.log("Partial: "+ JSON.stringify(partialConfig));
console.log("Required: "+ JSON.stringify(requiredConfig));
console.log("Readonly: "+ JSON.stringify(readonlyConfig));
**Output:**
Partial: {"host":"localhost"}Required: {"host":"localhost","port":8080}Readonly: {"host":"localhost","port":8080}
> **Utility Types:** The TypeScript standard library provides many utility types based on intersection types and mapped types, such as Partial, Required, Readonly, etc.
* * *
## Precautions
* **Incompatible types:** Intersecting incompatible types results in never
* **Precedence:** Union types have higher precedence than intersection types
* **Method conflicts:** If two types have methods with the same name, you need to handle the conflict manually
> **Best Practice:** Intersection types are suitable for combining multiple interfaces or types. When multiple inheritance is needed, prioritize intersection types over interface inheritance.
* * *
## Summary
Intersection types are a powerful type combination tool in TypeScript.
* **Syntax:** Use the `&` symbol to connect multiple types
* **Merging:** The new type contains members of all types
* **Mixin:** Can be used to implement class functionality composition
* **never:** Intersecting incompatible types results in the never type
> **Suggestion:** Reasonable use of intersection types can create flexible type combinations, but be careful to avoid the never type caused by unnecessary type intersections.
* * *
YouTip