0
0
Typescriptprogramming~15 mins

How intersection combines types in Typescript - Mechanics & Internals

Choose your learning style9 modes available
Overview - How intersection combines types
What is it?
Intersection types in TypeScript let you combine multiple types into one. This means a value must satisfy all the combined types at once. It's like merging different sets of rules into a single rulebook that the value must follow. This helps create precise and flexible types for complex data.
Why it matters
Without intersection types, you would struggle to express that something needs to meet multiple requirements simultaneously. This would make your code less safe and harder to understand. Intersection types help catch errors early and make your programs clearer by describing exactly what shapes data must have.
Where it fits
Before learning intersection types, you should understand basic types and union types in TypeScript. After mastering intersections, you can explore advanced type features like mapped types, conditional types, and type guards to write even more powerful type-safe code.
Mental Model
Core Idea
An intersection type combines multiple types so a value must have all their properties and behaviors at the same time.
Think of it like...
Imagine you have two job descriptions, one for a chef and one for a waiter. An intersection type is like hiring someone who must do both jobs perfectly, not just one or the other.
TypeA & TypeB
  ├─ Properties from TypeA
  ├─ Properties from TypeB
  └─ Value must satisfy both sets
Build-Up - 7 Steps
1
FoundationBasic type combination concept
🤔
Concept: Intersection types combine two or more types into one that requires all combined properties.
In TypeScript, you use the & symbol to create an intersection type. For example, type A = { name: string }; type B = { age: number }; type C = A & B; means C must have both name and age properties.
Result
A value of type C must have both a string 'name' and a number 'age'.
Understanding that & means 'and' helps you see intersection types as combining requirements, not alternatives.
2
FoundationDifference from union types
🤔
Concept: Intersection types require all combined types, while union types require any one of them.
Union types use | and mean a value can be one type or another. Intersection types use & and mean a value must be all types at once. For example, type U = A | B means name or age, but type I = A & B means both name and age.
Result
Union types allow more flexibility but less strictness; intersection types are stricter and more precise.
Knowing the difference prevents confusion and helps you choose the right tool for your type needs.
3
IntermediateCombining object types with intersections
🤔Before reading on: do you think intersecting two object types merges their properties or picks one?
Concept: When intersecting object types, the resulting type has all properties from each type combined.
If you have type X = { a: string } and type Y = { b: number }, then type Z = X & Y means Z has both 'a' and 'b'. You can use this to build complex objects from smaller parts.
Result
Z requires both properties 'a' (string) and 'b' (number) to be present.
Understanding property merging helps you design modular and reusable types.
4
IntermediateHandling overlapping properties in intersections
🤔Before reading on: if two types have the same property with different types, does intersection accept both or cause error?
Concept: If intersected types share a property with different types, the property type becomes the intersection of those types, which can cause conflicts.
For example, type A = { x: string }; type B = { x: number }; type C = A & B; means property 'x' must be both string and number, which is impossible, so no value can satisfy C.
Result
The intersection type becomes impossible to fulfill if property types conflict.
Knowing this prevents subtle bugs and helps you design compatible types.
5
IntermediateUsing intersections with functions and primitives
🤔
Concept: Intersection types can combine function types or primitives, but the result depends on compatibility.
For example, type F1 = (x: number) => string; type F2 = (x: string) => number; type F3 = F1 & F2; means a function that can be called with number or string and returns both string and number, which is tricky and often unused.
Result
Intersections of incompatible function types are rarely useful and can cause confusion.
Understanding limitations helps you avoid overcomplicating your types.
6
AdvancedIntersection types with generics and type inference
🤔Before reading on: do you think intersections with generics make type inference easier or more complex?
Concept: Using intersection types with generics allows flexible yet precise typing but can complicate type inference.
For example, function merge(a: T, b: U): T & U { return { ...a, ...b }; } returns a value that combines both inputs. TypeScript infers T and U from arguments, producing a merged type.
Result
You get a new object type with all properties from both inputs, inferred automatically.
Knowing how intersections work with generics unlocks powerful reusable functions.
7
ExpertIntersection types and distributive conditional types
🤔Before reading on: do intersection types distribute over unions automatically or not?
Concept: Intersection types interact with conditional types in complex ways, especially with unions, affecting how types distribute and combine.
TypeScript distributes conditional types over unions, but intersections can change this behavior. For example, conditional types like T extends U ? X : Y behave differently when T is an intersection, affecting type inference and narrowing.
Result
Understanding this helps write advanced type logic that behaves as expected in complex scenarios.
Mastering this subtlety prevents confusing type errors and enables expert-level type programming.
Under the Hood
TypeScript's compiler treats intersection types as a set of constraints that a value must satisfy simultaneously. Internally, it merges the properties and methods of all intersected types into one composite type. When checking values, it verifies that all parts of the intersection are met. Conflicts in property types cause the intersection to become impossible to satisfy, leading to type errors.
Why designed this way?
Intersection types were introduced to express precise combinations of types without duplicating code. They allow modular type composition, improving code reuse and safety. Alternatives like unions express 'either-or' but not 'both-and'. The design balances expressiveness with compiler complexity, enabling powerful static checks.
┌─────────────┐   ┌─────────────┐
│   Type A    │   │   Type B    │
│ { a: string }│   │ { b: number }│
└──────┬──────┘   └──────┬──────┘
       │                 │
       └─────&───────────┘
             │
     ┌─────────────┐
     │ Intersection│
     │ { a: string,│
     │   b: number }│
     └─────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does an intersection type mean a value can be one type or the other? Commit yes or no.
Common Belief:Intersection types mean a value can be either one type or another, like a union.
Tap to reveal reality
Reality:Intersection types require the value to satisfy all types at once, not just one.
Why it matters:Confusing intersection with union leads to incorrect assumptions about what values are allowed, causing bugs and type errors.
Quick: If two intersected types have the same property with different types, does TypeScript pick one or error? Commit your answer.
Common Belief:TypeScript will pick one property type or merge them safely without error.
Tap to reveal reality
Reality:TypeScript requires the property to satisfy both types, which can be impossible and cause errors.
Why it matters:Ignoring this causes unexpected type conflicts and makes code harder to debug.
Quick: Can intersection types be used to combine primitive types like string & number? Commit yes or no.
Common Belief:You can freely combine any types with intersections, including primitives like string & number.
Tap to reveal reality
Reality:Intersecting incompatible primitives results in a type that no value can satisfy, effectively 'never'.
Why it matters:Misusing intersections with primitives can create unreachable code paths and confusing errors.
Quick: Do intersection types always make type inference simpler? Commit yes or no.
Common Belief:Using intersection types always helps TypeScript infer types more easily.
Tap to reveal reality
Reality:Intersections can complicate inference, especially with generics and conditional types.
Why it matters:Overusing intersections without understanding inference can lead to confusing compiler errors.
Expert Zone
1
Intersection types can cause unexpected 'never' types when property types conflict, which is a subtle source of bugs.
2
When combining function types with intersections, the resulting type requires a function compatible with all signatures, which is often impossible.
3
Intersections interact with conditional and mapped types in complex ways that affect distributive behavior and inference.
When NOT to use
Avoid intersection types when combining incompatible types or primitives that cannot logically coexist. Use union types for alternatives or discriminated unions for variant data. For complex transformations, consider mapped or conditional types instead.
Production Patterns
In real-world TypeScript code, intersections are used to compose mixins, combine interfaces for complex objects, and create flexible utility types. They enable modular design by merging capabilities from multiple sources, such as combining user data with permissions or configuration options.
Connections
Set theory
Intersection types correspond to set intersections where elements must belong to all sets simultaneously.
Understanding set intersections clarifies why intersection types require all conditions, not just one.
Database schema design
Combining multiple table schemas into one view is like intersecting types to require all fields together.
Knowing how database joins merge columns helps grasp how intersection types merge properties.
Logic AND operator
Intersection types behave like logical AND, requiring all conditions to be true at once.
Recognizing this logical pattern helps predict how intersection types combine constraints.
Common Pitfalls
#1Combining types with conflicting property types causes impossible types.
Wrong approach:type A = { x: string }; type B = { x: number }; type C = A & B; const val: C = { x: 'hello' }; // Error: Type 'string' is not assignable to 'never'
Correct approach:type A = { x: string }; type B = { y: number }; type C = A & B; const val: C = { x: 'hello', y: 42 }; // Correct
Root cause:Misunderstanding that intersecting conflicting property types creates a type no value can satisfy.
#2Using intersection when union is needed for alternatives.
Wrong approach:type A = { kind: 'a' }; type B = { kind: 'b' }; type C = A & B; const val: C = { kind: 'a' }; // Error: missing 'b' kind
Correct approach:type A = { kind: 'a' }; type B = { kind: 'b' }; type C = A | B; const val: C = { kind: 'a' }; // Correct
Root cause:Confusing intersection (AND) with union (OR) leads to wrong type choices.
#3Expecting intersection types to simplify type inference always.
Wrong approach:function combine(a: T, b: U): T & U { return { ...a, ...b }; } const result = combine({ a: 1 }, { b: 'x' }); // Later complex inference errors appear
Correct approach:Use explicit type annotations or simpler types when inference is complex: const result: { a: number; b: string } = combine({ a: 1 }, { b: 'x' });
Root cause:Not realizing intersections can complicate inference, requiring explicit hints.
Key Takeaways
Intersection types combine multiple types so a value must satisfy all at once, not just one.
They merge properties from all types, but conflicting property types cause impossible types.
Intersection differs from union types, which allow any one of multiple types.
Using intersections with generics enables powerful, flexible type-safe functions.
Understanding intersections deeply helps avoid subtle bugs and write clearer TypeScript code.