Intersection Types
When you need ALL the things, not just some.
If union types are "this OR that," intersection types are "this AND that." An intersection type combines MULTIPLE types into ONE — the result must satisfy ALL of them simultaneously. Every single type in the intersection must be happy, or nothing works.
Think of it this way: Hyderabadi biryani itself is an intersection! It's NOT just rice OR just meat OR just spices — it's rice AND meat AND spices AND dum cooking AND saffron — ALL combined into one dish. If you miss even one ingredient, it's not Hyderabadi biryani anymore. The dish must satisfy every single ingredient type at the same time. You can't skip the saffron and still call it authentic!
Another analogy: Getting into HITEC City — you need a laptop AND an ID badge AND a mask AND a valid reason to enter. ALL conditions must be met. If you have a laptop but no badge, security won't let you in. Having three out of four is not enough — every condition is mandatory.
An intersection type { name: string } & { age: number } means the value MUST have both name: string AND age: number. It's the COMBINATION of all properties from all types in the intersection. Missing even one property? Type error. No compromises.
The & operator creates an intersection type. The syntax is straightforward and elegant: type Combined = TypeA & TypeB. Let's see the basic examples in action:
type Name = { name: string };
type Age = { age: number };
type Person = Name & Age;
// ✅ Works — has both!
const p1: Person = {
name: "Imran",
age: 25
};
// ❌ Error — missing age!
const p2: Person = {
name: "Imran"
};
You can chain multiple intersections together. The resulting type must satisfy ALL of them:
type A = { a: string };
type B = { b: number };
type C = { c: boolean };
type ABC = A & B & C;
// Must have a, b, AND c!
Intersections work beautifully with type aliases — each alias describes one "concern" and you compose them together. Here's a real-world pattern you'll see constantly in production codebases:
type HasId = { id: string };
type HasTimestamps = {
createdAt: Date;
updatedAt: Date;
};
type Entity = HasId & HasTimestamps;
// Every entity: id + timestamps
Every entity has an id AND timestamps. This is composability — small types building bigger types! Each type is responsible for one thing, and you mix them as needed. Think of it like building with Lego blocks — each block has a purpose, and together they create something complete.
The real power comes when you combine intersections and unions together. You've already seen unions — "this OR that." Now add intersections — "this AND that." Together, they create sophisticated type systems that model real-world data accurately.
Consider a common pattern: type Admin = User & { role: "admin"; permissions: string[] } — an Admin is a User AND has admin-specific fields. The intersection adds extra requirements on top of the base type.
Here's a realistic API response pattern used in production apps everywhere:
type SuccessResponse = {
status: "success";
data: string;
};
type ErrorResponse = {
status: "error";
message: string;
};
type ApiResponse =
| SuccessResponse
| ErrorResponse;
This is a union of two distinct shapes — the response is either success OR error. You can also create intersections inline: function process(input: { name: string } & { age: number }) — but this is less readable than using type aliases. Prefer named types for clarity.
Intersection of function types is also valid TypeScript:
type Log = (msg: string) => void;
type Send = (msg: string) => boolean;
type LogAndSend = Log & Send;
// Must satisfy BOTH signatures
A function satisfying BOTH signatures — this is advanced and rare, but TypeScript allows it. The most common and practical use case by far is composing object types — combining multiple "aspects" or "concerns" into one complete type. Think of it like building a thali — each small dish is a type, and the full thali is the intersection of all of them!
Intersections have some sneaky traps that catch even experienced developers. Let's walk through them one by one so you don't get caught in interviews or production code!
Trap 1: Impossible intersections. type Impossible = string & number — this results in never because nothing can be both a string AND a number at the same time! TypeScript doesn't always warn you about this loudly. The type silently becomes never, and you can't create a value of type never.
type Impossible = string & number;
// TypeScript quietly makes this: never
const x: Impossible = "hello";
// ❌ Type error!
Trap 2: Property conflicts. What happens when two types share the same property name but with different types?
type A = { name: string };
type B = { name: number };
type C = A & B;
// C.name is: string & number = never!
The property exists but you can NEVER assign a value to it. This is a silent trap — TypeScript allows the intersection but the property becomes unusable. The object must have name, but no value satisfies both string and number simultaneously.
Trap 3: Conflicting literals.
type Cat = { kind: "cat" };
type Dog = { kind: "dog" };
type CatDog = Cat & Dog;
// kind: "cat" & "dog" = never
You can't satisfy both! "cat" & "dog" is never — there's no string that is both "cat" and "dog" at the same time.
Trap 4: Order doesn't matter. A & B is the same as B & A. Intersection is commutative, just like in mathematics.
Trap 5: Intersection vs union for objects. A | B means "A OR B" (needs properties from ONE). A & B means "A AND B" (needs properties from BOTH). Don't mix them up — this is the most common confusion developers face when learning intersections!
Let's put it all together with a comprehensive cheatsheet and recap of everything we've learned about intersection types.
Here's your quick reference table:
A & B→ Must satisfy both A and BA & B & C→ Must satisfy all threestring & number→never(impossible){a: string} & {a: number}→{a: never}(conflict)A & Bsame asB & A(commutative)
Key Rules to Remember:
- 1.
&means AND — the value must satisfy ALL types in the intersection, not just one. Every property from every type must be present and correctly typed. - 2. Intersection combines properties — the resulting type has ALL properties from ALL intersected types. It's purely additive — more types means more required properties.
- 3. Conflicting properties become
never— if two types share a property name with different types, that property becomesnever. You can't assign any value to it. The intersection still "works," but that property is dead. - 4. Order doesn't matter —
A & Bis identical toB & A. Intersection is commutative, just like in mathematics. - 5. Use for composing small types — the best use of intersections is building big types from small, focused type aliases. Each alias handles one concern, and you combine them as needed.
- 6. Don't intersect primitive types —
string & number,boolean & number, etc. always result innever. It's meaningless and almost certainly a bug in your type design.
The Golden Rule: "Intersection is the biryani recipe — ALL ingredients must be present, not just one. But don't mix ingredients that clash, or you get nothing!"
Key Points — Intersection Types
- Intersection types combine multiple types using the & operator — the result must satisfy ALL types
- The & operator is additive: the resulting type has ALL properties from ALL intersected types
- Conflicting properties become never — impossible to assign any value to them
- Best used for composing small, focused type aliases into bigger, complete types
- string & number = never — never intersect primitive types, it is meaningless
- A & B is the same as B & A — intersection is commutative
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login