A Generic Interface allows you to define an interface that takes a type parameter, making it reusable with different types while keeping type safety.
✅ Basic Syntax
interface Box<T> {
value: T;
}
const numberBox: Box<number> = { value: 123 };
const stringBox: Box<string> = { value: "hello" };Here:
Box<T>is a generic interface.Tcan be replaced with any type when used.
📦 Generic Interface with Arrays
interface Collection<T> {
items: T[];
add(item: T): void;
}
const stringCollection: Collection<string> = {
items: ["apple", "banana"],
add(item) {
this.items.push(item);
},
};🔁 Multiple Type Parameters
interface Pair<K, V> {
key: K;
value: V;
}
const pair: Pair<string, number> = {
key: "age",
value: 25,
};⛓️ Generic Interface with Constraints
You can restrict the types passed into the generic using extends.
interface HasLength {
length: number;
}
interface Wrapper<T extends HasLength> {
data: T;
}
const wrappedString: Wrapper<string> = { data: "hello" };
const wrappedArray: Wrapper<number[]> = { data: [1, 2, 3] };
// ❌ Error: number doesn’t have length
// const wrappedNumber: Wrapper<number> = { data: 123 };⚙️ Default Type for Generics
interface ResponseData<T = any> {
data: T;
status: number;
}
const defaultResponse: ResponseData = {
data: "some data",
status: 200,
};🧠 When to Use Generic Interfaces
Use them when:
You want to define reusable data structures (e.g., API response, form values, input props).
You need type safety but flexibility.
You want to abstract logic like in repositories, forms, or services.
🧪 Real-World Example: API Result
interface ApiResponse<T> {
status: "success" | "error";
data: T;
message?: string;
}
interface User {
id: number;
name: string;
}
const userResponse: ApiResponse<User> = {
status: "success",
data: { id: 1, name: "Tisha" },
};<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;
--ed-err: #f14c4c;
--run-bg: #2e7d46;
--run-bg-hover: #35924f;
--tok-kw: #c586c0;
--tok-type: #4ec9b0;
--tok-str: #ce9178;
--tok-num: #b5cea8;
--tok-punc: #d4d4d4;
--tok-cmt: #808080;
--tok-var: #ffffff;
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; }
.tabs { display: flex; justify-content: center; gap: 4px; margin-bottom: 1.1rem; flex-wrap: wrap; }
.tab-btn { font-family: var(--body-font); font-size: 0.82rem; font-weight: 500;
background: #ffffff; color: #2563eb; border: 1px solid #2563eb; padding: 0.65rem 1rem;
cursor: pointer; border-radius: 8px; }
.tab-btn.active { background: #2563eb; color: #ffffff; }
.tab-btn:hover:not(.active) { background: #eef3ff; }
.tab-panel { display: none; background: var(--ed-bg); border-radius: 8px;
padding: 1.1rem; }
.tab-panel.active { display: block; }
.code-window { background: var(--ed-bg); border: 1px solid #2f2f2f; border-radius: 8px;
overflow: hidden; margin-bottom: 1rem; }
.code-window:last-child { margin-bottom: 0; }
.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); }
.run-btn { display: inline-flex; align-items: center; gap: 0.35rem; background: var(--run-bg);
color: #fff; border: none; border-radius: 4px; padding: 0.32rem 0.7rem; font-size: 0.74rem;
font-family: var(--body-font); font-weight: 500; cursor: pointer; }
.run-btn:hover { background: var(--run-bg-hover); }
.run-btn svg { width: 10px; height: 10px; }
.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-num { color: var(--tok-num); }
.tok-punc { color: var(--tok-var); }
.tok-cmt { color: var(--tok-cmt); }
.tok-var { color: var(--tok-var); }
.console { padding: 0 1.1rem; max-height: 0; overflow: hidden; font-family: var(--mono-font);
font-size: 0.78rem; line-height: 1.65; transition: max-height 0.35s ease, padding 0.35s ease; }
.console.show { max-height: 260px; padding: 0 1.1rem 0.85rem; }
.console-line { color: var(--ed-out); }
.console-line.ok { color: var(--ed-ok); }
.console-line.err { color: var(--ed-err); }
.note-line { font-family: var(--body-font); font-size: 0.8rem; color: var(--ed-muted);
padding: 0 0.2rem; margin: 0; }
</style>
<h2 class="ts-header">Generic interfaces</h2>
<div class="tabs">
<button class="tab-btn active" data-tab="t1" type="button">Basic</button>
<button class="tab-btn" data-tab="t2" type="button">Arrays</button>
<button class="tab-btn" data-tab="t3" type="button">Multiple params</button>
<button class="tab-btn" data-tab="t4" type="button">Constraints</button>
<button class="tab-btn" data-tab="t5" type="button">Default type</button>
<button class="tab-btn" data-tab="t6" type="button">Real-world</button>
</div>
<div class="tab-panel active" id="t1">
<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">box.ts</span>
<button class="run-btn" id="boxBtn" type="button">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 3 20 12 6 21 6 3"/></svg>
run
</button>
</div>
<div class="code-body"><span class="tok-kw">interface</span> <span class="tok-type">Box</span><span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">></span> <span class="tok-punc">{</span>
<span class="tok-var">value</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">;</span>
<span class="tok-punc">}</span>
<span class="tok-kw">const</span> <span class="tok-var">numberBox</span><span class="tok-punc">:</span> <span class="tok-type">Box</span><span class="tok-punc"><</span><span class="tok-type">number</span><span class="tok-punc">></span> <span class="tok-punc">=</span> <span class="tok-punc">{</span> <span class="tok-var">value</span><span class="tok-punc">:</span> <span class="tok-num">123</span> <span class="tok-punc">};</span>
<span class="tok-kw">const</span> <span class="tok-var">stringBox</span><span class="tok-punc">:</span> <span class="tok-type">Box</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-punc">{</span> <span class="tok-var">value</span><span class="tok-punc">:</span> <span class="tok-str">"hello"</span> <span class="tok-punc">};</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">numberBox</span><span class="tok-punc">.</span><span class="tok-var">value</span><span class="tok-punc">,</span> <span class="tok-var">stringBox</span><span class="tok-punc">.</span><span class="tok-var">value</span><span class="tok-punc">);</span></div>
<div class="console" id="boxConsole"></div>
</div>
<p class="note-line">Box<T> is one shape that works for any T — picked fresh each time it's used.</p>
</div>
<div class="tab-panel" id="t2">
<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">collection.ts</span>
<button class="run-btn" id="colBtn" type="button">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 3 20 12 6 21 6 3"/></svg>
run
</button>
</div>
<div class="code-body"><span class="tok-kw">interface</span> <span class="tok-type">Collection</span><span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">></span> <span class="tok-punc">{</span>
<span class="tok-var">items</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">[];</span>
<span class="tok-var">add</span><span class="tok-punc">(</span><span class="tok-var">item</span><span class="tok-punc">:</span> <span class="tok-type">T</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">const</span> <span class="tok-var">stringCollection</span><span class="tok-punc">:</span> <span class="tok-type">Collection</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-punc">{</span>
<span class="tok-var">items</span><span class="tok-punc">:</span> <span class="tok-punc">[</span><span class="tok-str">"apple"</span><span class="tok-punc">,</span> <span class="tok-str">"banana"</span><span class="tok-punc">],</span>
<span class="tok-var">add</span><span class="tok-punc">(</span><span class="tok-var">item</span><span class="tok-punc">)</span> <span class="tok-punc">{</span>
<span class="tok-kw">this</span><span class="tok-punc">.</span><span class="tok-var">items</span><span class="tok-punc">.</span><span class="tok-var">push</span><span class="tok-punc">(</span><span class="tok-var">item</span><span class="tok-punc">);</span>
<span class="tok-punc">},</span>
<span class="tok-punc">};</span>
<span class="tok-var">stringCollection</span><span class="tok-punc">.</span><span class="tok-var">add</span><span class="tok-punc">(</span><span class="tok-str">"cherry"</span><span class="tok-punc">);</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">stringCollection</span><span class="tok-punc">.</span><span class="tok-var">items</span><span class="tok-punc">);</span></div>
<div class="console" id="colConsole"></div>
</div>
<p class="note-line">items and add() both lock to whatever T the interface was given — string here, throughout.</p>
</div>
<div class="tab-panel" id="t3">
<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">pair.ts</span>
<button class="run-btn" id="pairBtn" type="button">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 3 20 12 6 21 6 3"/></svg>
run
</button>
</div>
<div class="code-body"><span class="tok-kw">interface</span> <span class="tok-type">Pair</span><span class="tok-punc"><</span><span class="tok-type">K</span><span class="tok-punc">,</span> <span class="tok-type">V</span><span class="tok-punc">></span> <span class="tok-punc">{</span>
<span class="tok-var">key</span><span class="tok-punc">:</span> <span class="tok-type">K</span><span class="tok-punc">;</span>
<span class="tok-var">value</span><span class="tok-punc">:</span> <span class="tok-type">V</span><span class="tok-punc">;</span>
<span class="tok-punc">}</span>
<span class="tok-kw">const</span> <span class="tok-var">pair</span><span class="tok-punc">:</span> <span class="tok-type">Pair</span><span class="tok-punc"><</span><span class="tok-type">string</span><span class="tok-punc">,</span> <span class="tok-type">number</span><span class="tok-punc">></span> <span class="tok-punc">=</span> <span class="tok-punc">{</span>
<span class="tok-var">key</span><span class="tok-punc">:</span> <span class="tok-str">"age"</span><span class="tok-punc">,</span>
<span class="tok-var">value</span><span class="tok-punc">:</span> <span class="tok-num">25</span><span class="tok-punc">,</span>
<span class="tok-punc">};</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">pair</span><span class="tok-punc">.</span><span class="tok-var">key</span><span class="tok-punc">,</span> <span class="tok-var">pair</span><span class="tok-punc">.</span><span class="tok-var">value</span><span class="tok-punc">);</span></div>
<div class="console" id="pairConsole"></div>
</div>
<p class="note-line">K and V are independent — key and value can be two completely different types.</p>
</div>
<div class="tab-panel" id="t4">
<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">wrapper.ts</span>
<button class="run-btn" id="wrapBtn" type="button">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 3 20 12 6 21 6 3"/></svg>
run
</button>
</div>
<div class="code-body"><span class="tok-kw">interface</span> <span class="tok-type">HasLength</span> <span class="tok-punc">{</span>
<span class="tok-var">length</span><span class="tok-punc">:</span> <span class="tok-type">number</span><span class="tok-punc">;</span>
<span class="tok-punc">}</span>
<span class="tok-kw">interface</span> <span class="tok-type">Wrapper</span><span class="tok-punc"><</span><span class="tok-type">T</span> <span class="tok-kw">extends</span> <span class="tok-type">HasLength</span><span class="tok-punc">></span> <span class="tok-punc">{</span>
<span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">;</span>
<span class="tok-punc">}</span>
<span class="tok-kw">const</span> <span class="tok-var">wrappedString</span><span class="tok-punc">:</span> <span class="tok-type">Wrapper</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-punc">{</span> <span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-str">"hello"</span> <span class="tok-punc">};</span>
<span class="tok-kw">const</span> <span class="tok-var">wrappedArray</span><span class="tok-punc">:</span> <span class="tok-type">Wrapper</span><span class="tok-punc"><</span><span class="tok-type">number</span><span class="tok-punc">[]></span> <span class="tok-punc">=</span> <span class="tok-punc">{</span> <span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-punc">[</span><span class="tok-num">1</span><span class="tok-punc">,</span> <span class="tok-num">2</span><span class="tok-punc">,</span> <span class="tok-num">3</span><span class="tok-punc">]</span> <span class="tok-punc">};</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">wrappedString</span><span class="tok-punc">.</span><span class="tok-var">data</span><span class="tok-punc">.</span><span class="tok-var">length</span><span class="tok-punc">,</span> <span class="tok-var">wrappedArray</span><span class="tok-punc">.</span><span class="tok-var">data</span><span class="tok-punc">.</span><span class="tok-var">length</span><span class="tok-punc">);</span>
<span class="tok-kw">const</span> <span class="tok-var">wrappedNumber</span><span class="tok-punc">:</span> <span class="tok-type">Wrapper</span><span class="tok-punc"><</span><span class="tok-type">number</span><span class="tok-punc">></span> <span class="tok-punc">=</span> <span class="tok-punc">{</span> <span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-num">123</span> <span class="tok-punc">};</span></div>
<div class="console" id="wrapConsole"></div>
</div>
<p class="note-line">extends HasLength lets T be a string or an array, but blocks a plain number.</p>
</div>
<div class="tab-panel" id="t5">
<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">response.ts</span>
<button class="run-btn" id="respBtn" type="button">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 3 20 12 6 21 6 3"/></svg>
run
</button>
</div>
<div class="code-body"><span class="tok-kw">interface</span> <span class="tok-type">ResponseData</span><span class="tok-punc"><</span><span class="tok-type">T</span> <span class="tok-punc">=</span> <span class="tok-kw">any</span><span class="tok-punc">></span> <span class="tok-punc">{</span>
<span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">;</span>
<span class="tok-var">status</span><span class="tok-punc">:</span> <span class="tok-type">number</span><span class="tok-punc">;</span>
<span class="tok-punc">}</span>
<span class="tok-kw">const</span> <span class="tok-var">defaultResponse</span><span class="tok-punc">:</span> <span class="tok-type">ResponseData</span> <span class="tok-punc">=</span> <span class="tok-punc">{</span>
<span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-str">"some data"</span><span class="tok-punc">,</span>
<span class="tok-var">status</span><span class="tok-punc">:</span> <span class="tok-num">200</span><span class="tok-punc">,</span>
<span class="tok-punc">};</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">defaultResponse</span><span class="tok-punc">.</span><span class="tok-var">data</span><span class="tok-punc">,</span> <span class="tok-var">defaultResponse</span><span class="tok-punc">.</span><span class="tok-var">status</span><span class="tok-punc">);</span></div>
<div class="console" id="respConsole"></div>
</div>
<p class="note-line">Leaving off <T> entirely falls back to any — convenient, but it gives up type safety on data.</p>
</div>
<div class="tab-panel" id="t6">
<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">api-response.ts</span>
<button class="run-btn" id="apiBtn" type="button">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="6 3 20 12 6 21 6 3"/></svg>
run
</button>
</div>
<div class="code-body"><span class="tok-kw">interface</span> <span class="tok-type">ApiResponse</span><span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">></span> <span class="tok-punc">{</span>
<span class="tok-var">status</span><span class="tok-punc">:</span> <span class="tok-str">"success"</span> <span class="tok-punc">|</span> <span class="tok-str">"error"</span><span class="tok-punc">;</span>
<span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">;</span>
<span class="tok-var">message</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">interface</span> <span class="tok-type">User</span> <span class="tok-punc">{</span>
<span class="tok-var">id</span><span class="tok-punc">:</span> <span class="tok-type">number</span><span class="tok-punc">;</span>
<span class="tok-var">name</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">const</span> <span class="tok-var">userResponse</span><span class="tok-punc">:</span> <span class="tok-type">ApiResponse</span><span class="tok-punc"><</span><span class="tok-type">User</span><span class="tok-punc">></span> <span class="tok-punc">=</span> <span class="tok-punc">{</span>
<span class="tok-var">status</span><span class="tok-punc">:</span> <span class="tok-str">"success"</span><span class="tok-punc">,</span>
<span class="tok-var">data</span><span class="tok-punc">:</span> <span class="tok-punc">{</span> <span class="tok-var">id</span><span class="tok-punc">:</span> <span class="tok-num">1</span><span class="tok-punc">,</span> <span class="tok-var">name</span><span class="tok-punc">:</span> <span class="tok-str">"Tisha"</span> <span class="tok-punc">},</span>
<span class="tok-punc">};</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">userResponse</span><span class="tok-punc">.</span><span class="tok-var">status</span><span class="tok-punc">,</span> <span class="tok-var">userResponse</span><span class="tok-punc">.</span><span class="tok-var">data</span><span class="tok-punc">.</span><span class="tok-var">name</span><span class="tok-punc">);</span></div>
<div class="console" id="apiConsole"></div>
</div>
<p class="note-line">One ApiResponse<T> interface covers every endpoint — just swap in the T for what that endpoint returns.</p>
</div>
<script>
(function () {
var wrapper = document.currentScript.closest('.infographic-ts')
|| document.querySelector('.infographic-ts');
var root = wrapper;
var tabBtns = root.querySelectorAll('.tab-btn');
var panels = root.querySelectorAll('.tab-panel');
tabBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
var target = btn.getAttribute('data-tab');
tabBtns.forEach(function (b) { b.classList.toggle('active', b === btn); });
panels.forEach(function (p) { p.classList.toggle('active', p.id === target); });
});
});
function line(consoleEl, cls, text) {
var el = document.createElement('div');
el.className = 'console-line ' + (cls || '');
el.textContent = text;
consoleEl.appendChild(el);
}
function bind(id, consoleId, cb) {
var btn = root.querySelector('#' + id);
var c = root.querySelector('#' + consoleId);
btn.addEventListener('click', function () {
c.innerHTML = '';
c.classList.add('show');
cb(c);
setTimeout(function () {
c.scrollIntoView({ behavior: 'smooth', block: 'end' });
}, 50);
});
}
bind('boxBtn', 'boxConsole', function (c) {
line(c, 'ok', '123 hello');
});
bind('colBtn', 'colConsole', function (c) {
line(c, 'ok', "[ 'apple', 'banana', 'cherry' ]");
});
bind('pairBtn', 'pairConsole', function (c) {
line(c, 'ok', 'age 25');
});
bind('wrapBtn', 'wrapConsole', function (c) {
line(c, 'ok', '5 3');
line(c, 'err', "Wrapper<number> \u2192 Error: Type 'number' does not satisfy the constraint 'HasLength'.");
});
bind('respBtn', 'respConsole', function (c) {
line(c, 'ok', 'some data 200');
});
bind('apiBtn', 'apiConsole', function (c) {
line(c, 'ok', 'success Tisha');
});
})();
</script>
</div>📌 Summary
Feature | Example |
|---|---|
Basic Generic Interface |
|
With Arrays |
|
Multiple Parameters |
|
Constraints |
|
Default Types |
|