Suggest an editImprove this articleRefine the answer for “Intersection types in TypeScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Intersection type** combines multiple types into one using `&`. A value must satisfy all combined types at once. ```typescript type Person = { name: string } & { age: number }; const alice: Person = { name: "Alice", age: 25 }; // both fields required ``` **Key point:** conflicting properties like `string & number` collapse to `never`.Shown above the full answer for quick recall.Answer (EN)Image**Intersection type** - a TypeScript type created with `&` that requires a value to satisfy every combined type at once. ## Theory ### TL;DR - Think of a Swiss Army knife: every separate gadget's tools packed into one object. You get all capabilities, but the object must carry all of them. - `&` requires ALL properties from every combined type. `|` requires only one type to match. - Nested types intersect deeply. `{data: {x: number}} & {data: {y: string}}` gives `{data: {x: number; y: string}}`, not a replacement. - Conflicting primitives (`string & number`) become `never`. That is a compile error, not a runtime one. - Use `&` to compose object shapes from existing types: props + theme, user + admin, base config + db config. ### Quick example ```typescript type Name = { name: string }; type Age = { age: number }; type Person = Name & Age; // must have BOTH name and age const alice: Person = { name: "Alice", age: 25 }; // ✅ works const bob: Person = { name: "Bob" }; // ❌ Error: missing 'age' console.log(alice.name); // "Alice" console.log(alice.age); // 25 ``` `Person` is not a union of possibilities. It is one strict type that demands every property from `Name` and `Age` at the same time. ### Key difference from union types With `A | B`, a value needs to match only one of the types. With `A & B`, it must match both simultaneously. So a union might block you from accessing `propA` without a type guard, while an intersection makes `propA` and `propB` always directly accessible. ### When to use - Role-based types: `Admin & User` where an admin has extra privileges but also all user fields. - Express requests: `Request & { user: User }` in auth middleware (Passport.js patterns). - React component props: `ButtonProps & ThemeProps` when one component accepts both sets. - Avoid when types share a property with incompatible value types. That property becomes `never`. ### Intersection vs Union | Aspect | `A & B` | `A \| B` | |---|---|---| | Requirement | Must match all types | Must match any one type | | Properties you get | All from A and all from B | Only common properties guaranteed | | Access safety | `obj.propA` and `obj.propB` always safe | Type guard needed: `if ('propA' in obj)` | | Conflicting property | Becomes `never` | Not applicable | | Use case | Composing objects | Representing alternatives | ### How the compiler handles this TypeScript evaluates `A & B` at compile time only. No runtime cost. The compiler merges required properties from all combined types into the result. Optional properties stay optional. When two types share the same property key with incompatible value types, that property becomes `never` in the intersection. The compiled JavaScript sees plain objects with no trace of intersection logic. One thing I have seen trip up developers: TypeScript intersects nested types deeply, not shallowly. `{ data: { x: number } } & { data: { y: string } }` gives `{ data: { x: number; y: string } }`, not a replacement of `data`. Engineers coming from plain JavaScript often assume `B` overwrites `A` here, the way `Object.assign` would. It does not. ### Common mistakes **Assuming nested properties overwrite:** ```typescript type A = { data: { x: number } }; type B = { data: { y: string } }; type Merged = A & B; // data: { x: number; y: string } -- NOT just { y: string } const bad: Merged = { data: { x: 1 } }; // ❌ missing 'y' const ok: Merged = { data: { x: 1, y: 'hi' } }; // ✅ ``` If you need override behavior, use `Pick<B, 'data'> & Omit<A, 'data'>` instead. **Intersecting incompatible primitives:** ```typescript type ID = string & number; // never const id: ID = 'abc'; // ❌ type 'never' has no valid assignments ``` For branded string types, use `string & { readonly brand: unique symbol }` instead. **Optional vs required conflict:** ```typescript type OptA = { prop?: string }; type ReqB = { prop: number }; type Both = OptA & ReqB; // prop becomes required number ``` The intersection always takes the stricter side. Optional loses to required. ### Real-world usage - React: `ButtonProps & { variant: 'primary' | 'secondary' }` in component libraries like Material-UI. - Express: `Request & { user: User }` in Passport.js middleware patterns. - Redux Toolkit: `PayloadAction<string> & { meta: { timestamp: number } }` for typed actions. - Zod: `z.intersection(schemaA, schemaB)` mirrors this behavior at the schema level. ### Follow-up questions **Q:** What is the difference between `type A = B & C` and `interface A extends B, C`? **A:** Both produce equivalent types in most cases. `interface` supports declaration merging, so you can reopen it later to add properties. `type` is fixed after definition. For object shapes in shared libraries, `interface` is often more flexible. **Q:** What happens when you write `string & number`? **A:** It becomes `never`. No value can satisfy both primitive types at once, so the type is uninhabitable. **Q:** Can you intersect a union with another type? **A:** Yes. TypeScript distributes: `(A | B) & C` becomes `(A & C) | (B & C)`. This is useful when you need to narrow a union. **Q:** Does intersection have any runtime cost? **A:** None. TypeScript erases all type information during compilation. V8 sees plain JavaScript objects. ## Examples ### Basic: combining two object types ```typescript type Address = { street: string; city: string; }; type ContactInfo = { email: string; phone: string; }; type UserProfile = Address & ContactInfo; const user: UserProfile = { street: '123 Main St', city: 'Kyiv', email: 'user@example.com', phone: '+380 67 000 0000', }; // all four fields are required ``` Skip any one field and the compiler errors immediately. No runtime check needed. ### Intermediate: React component with combined props ```typescript interface ButtonProps { onClick: () => void; children: React.ReactNode; } interface ThemeProps { variant: 'primary' | 'secondary'; size: 'small' | 'large'; } type ThemedButtonProps = ButtonProps & ThemeProps; const ThemedButton: React.FC<ThemedButtonProps> = ({ onClick, children, variant, size, }) => ( <button className={`${variant} ${size}`} onClick={onClick}> {children} </button> ); // <ThemedButton variant="primary" size="large" onClick={() => {}}>Submit</ThemedButton> ``` TypeScript errors if `variant` or `onClick` is missing. IntelliSense shows all four props in autocomplete. Keeping `ButtonProps` and `ThemeProps` separate means each can be reused independently across other components.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.