YouTip LogoYouTip

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. * * *
← Ts MigrationTs Class Inheritance β†’