An Intersection Type combines multiple types into one. The resulting type will have all properties from each type.
✅ Syntax
type A = { name: string };
type B = { age: number };
type Person = A & B;
const user: Person = {
name: "Tisha",
age: 22
};This Person must have both name and age.
🔍 Use Case: Combining Object Types
type HasEmail = { email: string };
type HasPhone = { phone: string };
type ContactInfo = HasEmail & HasPhone;
const contact: ContactInfo = {
email: "test@example.com",
phone: "1234567890"
};🧠 Intersection vs Union
Feature | Union (|) | Intersection (&) |
|---|---|---|
Meaning | Either type A or type B | Must satisfy both type A and B |
Usage | When value can be of either type | When value must have all properties |
Real example | "success" I "error" (status flags) | {name} & {email} (merged props) |
🔒 With Interfaces
interface Admin {
role: string;
}
interface User {
name: string;
}
type AdminUser = Admin & User;
const admin: AdminUser = {
name: "Riya",
role: "Super Admin"
};⚠️ Conflicting Properties
Be cautious: if the same property exists in both types but with different types, you’ll get an error.
type A = { id: number };
type B = { id: string };
type C = A & B; // ❌ Error: Conflicting types for `id`✅ Combining with Functions
You can intersect function types to create overloaded functions:
type Loggable = {
log: () => void;
};
type Printable = {
print: () => void;
};
type LoggerPrinter = Loggable & Printable;
const item: LoggerPrinter = {
log() {
console.log("Logging...");
},
print() {
console.log("Printing...");
}
};🎯 Practical Use Case: Props Composition in React (for frontend devs)
<div class="infographic-ts" id="infographic-ts">
<style>
.infographic-ts {
--body-font: system-ui, -apple-system, sans-serif;
--mono-font: ui-monospace, SFMono-Regular, Consolas, "Courier New", monospace;
--ed-bg: #1e1e1e;
--ed-bar: #2a2a2a;
--ed-out: #d4d4d4;
--ed-muted: #8a8a8a;
--ed-ok: #4ec9b0;
--tok-kw: #c586c0;
--tok-type: #4ec9b0;
--tok-str: #ce9178;
--tok-cmt: #808080;
--tok-var: #ffffff;
--accent: #2563eb;
--coral: #ce9178;
max-width: 680px;
margin: 0 auto;
box-sizing: border-box;
background: transparent;
font-family: var(--body-font);
}
.infographic-ts * { box-sizing: border-box; }
.ts-header { font-family: 'Georgia', 'Fraunces', serif; font-weight: 700;
font-size: 1.9rem; letter-spacing: 0.01em; color: inherit; text-align: center;
margin: 0 0 1.4rem; }
.code-window { background: var(--ed-bg); border: 1px solid #2f2f2f; border-radius: 8px;
overflow: hidden; margin-bottom: 1.25rem; }
.code-topbar { display: flex; align-items: center; justify-content: space-between;
padding: 0.5rem 0.75rem; background: var(--ed-bar); }
.code-dots { display: flex; gap: 6px; }
.code-dot { width: 9px; height: 9px; border-radius: 50%; }
.code-dot.r { background: #ff5f57; }
.code-dot.y { background: #febc2e; }
.code-dot.g { background: #28c840; }
.code-filename { font-family: var(--mono-font); font-size: 0.74rem; color: var(--ed-muted); }
.code-body { padding: 0.85rem 1.1rem; font-family: var(--mono-font); font-size: 0.8rem;
line-height: 1.65; color: var(--ed-out); white-space: pre; overflow-x: auto; }
.tok-kw { color: var(--tok-kw); }
.tok-type { color: var(--tok-type); }
.tok-str { color: var(--tok-str); }
.tok-cmt { color: var(--tok-cmt); }
.tok-var { color: var(--tok-var); }
.tok-punc { color: var(--tok-var); }
.venn-card { background: var(--ed-bg); border: 1px solid #2f2f2f; border-radius: 8px;
padding: 1.5rem 1rem; margin-bottom: 1.25rem; }
.venn-wrap { position: relative; width: 460px; max-width: 100%; height: 230px; margin: 0 auto; }
.venn-circle { position: absolute; top: 20px; width: 260px; height: 180px; border-radius: 50%; }
.venn-circle.left { left: 0; background: rgba(91, 141, 239, 0.5); }
.venn-circle.right { left: 160px; background: rgba(206, 145, 120, 0.5); }
.venn-label { position: absolute; top: 70px; width: 130px; text-align: center; }
.venn-label.left { left: 5px; }
.venn-label.right { left: 325px; }
.venn-label.center { left: 165px; top: 46px; width: 130px; }
.venn-title { font-family: var(--mono-font); font-weight: 700; font-size: 0.76rem; margin: 0 0 0.4rem; }
.venn-label.left .venn-title { color: #8fb4ff; }
.venn-label.right .venn-title { color: #e8b697; }
.venn-label.center .venn-title { color: #fff; }
.venn-prop { font-family: var(--mono-font); font-size: 0.66rem; color: #f0f0f0; line-height: 1.55; }
.output-frame { background: #ffffff; border-radius: 8px; overflow: hidden; margin-bottom: 1rem;
box-shadow: 0 6px 18px rgba(0,0,0,0.18); }
.output-bar { display: flex; align-items: center; justify-content: space-between;
padding: 0.5rem 0.75rem; background: #2a2a2a; }
.output-label { font-family: var(--mono-font); font-size: 0.74rem; color: var(--ed-muted); }
.output-screen { padding: 2.75rem 1rem; display: flex; align-items: center; justify-content: center;
background: #fafafa; min-height: 110px; }
.demo-btn { font-family: var(--body-font); font-size: 0.95rem; font-weight: 600; color: #fff;
background: var(--accent); border: none; border-radius: 6px; padding: 0.7rem 1.7rem;
cursor: pointer; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.35); transition: transform 0.1s ease, opacity 0.15s ease; }
.demo-btn:hover { opacity: 0.92; }
.demo-btn:active { transform: scale(0.96); }
.terminal { background: var(--ed-bg); border-radius: 8px; overflow: hidden;
box-shadow: 0 6px 18px rgba(0,0,0,0.25); }
.term-body { font-family: var(--mono-font); font-size: 0.82rem; padding: 0.85rem 1.1rem;
min-height: 3rem; color: var(--ed-out); line-height: 1.7; }
.term-line { opacity: 0; transform: translateY(4px); transition: opacity 0.25s ease, transform 0.25s ease; }
.term-line.is-in { opacity: 1; transform: translateY(0); }
.term-prompt { color: var(--tok-cmt); }
.term-output { color: var(--ed-ok); font-weight: 600; }
.term-placeholder { color: var(--ed-muted); }
</style>
<div class="code-window">
<div class="code-topbar">
<div class="code-dots"><span class="code-dot r"></span><span class="code-dot y"></span><span class="code-dot g"></span></div>
<span class="code-filename">button-props.ts</span>
</div>
<div class="code-body"><span class="tok-kw">type</span> <span class="tok-type">ButtonProps</span> <span class="tok-punc">=</span> <span class="tok-punc">{</span>
<span class="tok-var">label</span><span class="tok-punc">:</span> <span class="tok-type">string</span><span class="tok-punc">;</span>
<span class="tok-punc">};</span>
<span class="tok-kw">type</span> <span class="tok-type">Clickable</span> <span class="tok-punc">=</span> <span class="tok-punc">{</span>
<span class="tok-var">onClick</span><span class="tok-punc">:</span> <span class="tok-punc">()</span> <span class="tok-punc">=></span> <span class="tok-type">void</span><span class="tok-punc">;</span>
<span class="tok-punc">};</span>
<span class="tok-kw">type</span> <span class="tok-type">FullButtonProps</span> <span class="tok-punc">=</span> <span class="tok-type">ButtonProps</span> <span class="tok-punc">&</span> <span class="tok-type">Clickable</span><span class="tok-punc">;</span></div>
</div>
<div class="venn-card">
<div class="venn-wrap">
<div class="venn-circle left"></div>
<div class="venn-circle right"></div>
<div class="venn-label left">
<p class="venn-title">ButtonProps</p>
<p class="venn-prop">label: string</p>
</div>
<div class="venn-label center">
<p class="venn-title">FullButtonProps</p>
<p class="venn-prop">label: string<br>onClick: () => void</p>
</div>
<div class="venn-label right">
<p class="venn-title">Clickable</p>
<p class="venn-prop">onClick: () => void</p>
</div>
</div>
</div>
<div class="output-frame">
<div class="output-bar">
<div class="code-dots"><span class="code-dot r"></span><span class="code-dot y"></span><span class="code-dot g"></span></div>
<span class="output-label">output</span>
<span style="width:39px"></span>
</div>
<div class="output-screen">
<button class="demo-btn" id="demoBtn" type="button">Save</button>
</div>
</div>
<div class="terminal">
<div class="output-bar">
<div class="code-dots"><span class="code-dot r"></span><span class="code-dot y"></span><span class="code-dot g"></span></div>
<span class="output-label">console</span>
<span style="width:39px"></span>
</div>
<div class="term-body" id="termBody"><span class="term-line is-in term-placeholder">a FullButtonProps object is rendered above — click it</span></div>
</div>
<script>
(function () {
var wrapper = document.currentScript.closest('.infographic-ts')
|| document.querySelector('.infographic-ts');
var root = wrapper;
var label = "Save";
var btn = root.querySelector('#demoBtn');
var term = root.querySelector('#termBody');
var cleared = false;
btn.addEventListener('click', function () {
if (!cleared) {
term.innerHTML = '';
cleared = true;
}
var line = document.createElement('div');
line.className = 'term-line';
line.innerHTML = '<span class="term-prompt">></span> <span class="term-output">' + label + ' clicked \u2014 onClick() fired</span>';
term.appendChild(line);
requestAnimationFrame(function () { line.classList.add('is-in'); });
term.scrollTop = term.scrollHeight;
setTimeout(function () {
term.scrollIntoView({ behavior: 'smooth', block: 'end' });
}, 50);
});
})();
</script>
</div>✅ Summary
Term | Meaning |
|---|---|
A & B | Must have all properties from both A and B |
Good for | Combining types, mixins, complex prop objects |
Caution | Avoid name conflicts with different types |