Generics let you create functions (or classes, interfaces, etc.) that work with any type, while still retaining type safety.
Instead of hardcoding types, you define a placeholder type like <T>.
✅ Basic Syntax
function identity<T>(value: T): T {
return value;
}
const num = identity<number>(10); // T = number
const str = identity<string>("hello"); // T = stringHere:
Tis a generic type parameter.TypeScript infers
Tif not explicitly provided.
🤖 With Type Inference
const result = identity("TypeScript"); // inferred as: string🧮 Generic Function with Arrays
function getFirstElement<T>(arr: T[]): T {
return arr[0];
}
getFirstElement([1, 2, 3]); // number
getFirstElement(["a", "b", "c"]); // string🛠️ Multiple Type Parameters
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
const merged = merge({ name: "Tisha" }, { age: 22 });
// inferred as: { name: string } & { age: number }🔐 Constraints with extends
You can limit what types are allowed for the generic:
function logLength<T extends { length: number }>(item: T): number {
return item.length;
}
logLength("hello"); // OK
logLength([1, 2, 3]); // OK
logLength({ length: 5 }); // OK
// logLength(123); ❌ Error: number doesn't have 'length'📦 Generic with Default Type
function createBox<T = string>(value: T): T[] {
return [value];
}
const box1 = createBox("hi"); // inferred as string[]
const box2 = createBox(42); // inferred as number[]🔄 Use in Arrow Functions
const wrapInArray = <T>(val: T): T[] => [val];
wrapInArray("apple"); // string[]
wrapInArray(true); // boolean[]🔍 Real-World Use Case
function fetchData<T>(url: string): Promise<T> {
return fetch(url).then(res => res.json());
}
interface User {
id: number;
name: string;
}
fetchData<User>("/api/user").then(user => {
console.log(user.name); // Type-safe access
});<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">Generics</h2>
<div class="tabs">
<button class="tab-btn active" data-tab="t1" type="button">Basic & inference</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 & arrow</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">identity.ts</span>
<button class="run-btn" id="basicBtn" 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">function</span> <span class="tok-var">identity</span><span class="tok-punc"><</span><span class="tok-type">T</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-type">T</span> <span class="tok-punc">{</span>
<span class="tok-kw">return</span> <span class="tok-var">value</span><span class="tok-punc">;</span>
<span class="tok-punc">}</span>
<span class="tok-kw">const</span> <span class="tok-var">num</span> <span class="tok-punc">=</span> <span class="tok-var">identity</span><span class="tok-punc"><</span><span class="tok-type">number</span><span class="tok-punc">>(</span><span class="tok-num">10</span><span class="tok-punc">);</span>
<span class="tok-kw">const</span> <span class="tok-var">str</span> <span class="tok-punc">=</span> <span class="tok-var">identity</span><span class="tok-punc"><</span><span class="tok-type">string</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">auto</span> <span class="tok-punc">=</span> <span class="tok-var">identity</span><span class="tok-punc">(</span><span class="tok-str">"TypeScript"</span><span class="tok-punc">);</span> <span class="tok-cmt">// T inferred as string</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">num</span><span class="tok-punc">,</span> <span class="tok-var">str</span><span class="tok-punc">,</span> <span class="tok-var">auto</span><span class="tok-punc">);</span></div>
<div class="console" id="basicConsole"></div>
</div>
<p class="note-line">T is filled in by the caller, explicitly or inferred from the argument — the return type always matches.</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">arrays.ts</span>
<button class="run-btn" id="arrBtn" 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">function</span> <span class="tok-var">getFirstElement</span><span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">>(</span><span class="tok-var">arr</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">[]):</span> <span class="tok-type">T</span> <span class="tok-punc">{</span>
<span class="tok-kw">return</span> <span class="tok-var">arr</span><span class="tok-punc">[</span><span class="tok-num">0</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">getFirstElement</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-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">getFirstElement</span><span class="tok-punc">([</span><span class="tok-str">"a"</span><span class="tok-punc">,</span> <span class="tok-str">"b"</span><span class="tok-punc">,</span> <span class="tok-str">"c"</span><span class="tok-punc">]));</span></div>
<div class="console" id="arrConsole"></div>
</div>
<p class="note-line">T is inferred from the array's element type, so the return type tracks whatever you pass in.</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">merge.ts</span>
<button class="run-btn" id="mergeBtn" 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">function</span> <span class="tok-var">merge</span><span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">,</span> <span class="tok-type">U</span><span class="tok-punc">>(</span><span class="tok-var">obj1</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">,</span> <span class="tok-var">obj2</span><span class="tok-punc">:</span> <span class="tok-type">U</span><span class="tok-punc">):</span> <span class="tok-type">T</span> <span class="tok-punc">&</span> <span class="tok-type">U</span> <span class="tok-punc">{</span>
<span class="tok-kw">return</span> <span class="tok-punc">{</span> <span class="tok-punc">...</span><span class="tok-var">obj1</span><span class="tok-punc">,</span> <span class="tok-punc">...</span><span class="tok-var">obj2</span> <span class="tok-punc">};</span>
<span class="tok-punc">}</span>
<span class="tok-kw">const</span> <span class="tok-var">merged</span> <span class="tok-punc">=</span> <span class="tok-var">merge</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">age</span><span class="tok-punc">:</span> <span class="tok-num">22</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">merged</span><span class="tok-punc">);</span></div>
<div class="console" id="mergeConsole"></div>
</div>
<p class="note-line">T and U are inferred separately from each argument; the result type is their intersection.</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">constraints.ts</span>
<button class="run-btn" id="constrBtn" 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">function</span> <span class="tok-var">logLength</span><span class="tok-punc"><</span><span class="tok-type">T</span> <span class="tok-kw">extends</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-var">item</span><span class="tok-punc">:</span> <span class="tok-type">T</span><span class="tok-punc">):</span> <span class="tok-type">number</span> <span class="tok-punc">{</span>
<span class="tok-kw">return</span> <span class="tok-var">item</span><span class="tok-punc">.</span><span class="tok-var">length</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">logLength</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">logLength</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-var">console</span><span class="tok-punc">.</span><span class="tok-var">log</span><span class="tok-punc">(</span><span class="tok-var">logLength</span><span class="tok-punc">({</span> <span class="tok-var">length</span><span class="tok-punc">:</span> <span class="tok-num">5</span> <span class="tok-punc">}));</span>
<span class="tok-var">logLength</span><span class="tok-punc">(</span><span class="tok-num">123</span><span class="tok-punc">);</span></div>
<div class="console" id="constrConsole"></div>
</div>
<p class="note-line">extends {`{ length: number }`} allows anything with a length property — and rejects anything without one.</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">default-type.ts</span>
<button class="run-btn" id="defaultBtn" 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">function</span> <span class="tok-var">createBox</span><span class="tok-punc"><</span><span class="tok-type">T</span> <span class="tok-punc">=</span> <span class="tok-type">string</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-type">T</span><span class="tok-punc">[]</span> <span class="tok-punc">{</span>
<span class="tok-kw">return</span> <span class="tok-punc">[</span><span class="tok-var">value</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">createBox</span><span class="tok-punc">(</span><span class="tok-str">"hi"</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">createBox</span><span class="tok-punc">(</span><span class="tok-num">42</span><span class="tok-punc">));</span></div>
<div class="console" id="defaultConsole"></div>
</div>
<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">arrow.ts</span>
<button class="run-btn" id="arrowBtn" 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">const</span> <span class="tok-var">wrapInArray</span> <span class="tok-punc">=</span> <span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">>(</span><span class="tok-var">val</span><span class="tok-punc">:</span> <span class="tok-type">T</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-punc">[</span><span class="tok-var">val</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">wrapInArray</span><span class="tok-punc">(</span><span class="tok-str">"apple"</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">wrapInArray</span><span class="tok-punc">(</span><span class="tok-kw">true</span><span class="tok-punc">));</span></div>
<div class="console" id="arrowConsole"></div>
</div>
<p class="note-line">= string gives T a fallback when it can't be inferred; arrow functions take a generic the same way.</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">fetch-data.ts</span>
<button class="run-btn" id="fetchBtn" 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">function</span> <span class="tok-var">fetchData</span><span class="tok-punc"><</span><span class="tok-type">T</span><span class="tok-punc">>(</span><span class="tok-var">url</span><span class="tok-punc">:</span> <span class="tok-type">string</span><span class="tok-punc">):</span> <span class="tok-type">Promise</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">return</span> <span class="tok-var">fetch</span><span class="tok-punc">(</span><span class="tok-var">url</span><span class="tok-punc">).</span><span class="tok-var">then</span><span class="tok-punc">(</span><span class="tok-var">res</span> <span class="tok-punc">=></span> <span class="tok-var">res</span><span class="tok-punc">.</span><span class="tok-var">json</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-var">fetchData</span><span class="tok-punc"><</span><span class="tok-type">User</span><span class="tok-punc">>(</span><span class="tok-str">"/api/user"</span><span class="tok-punc">).</span><span class="tok-var">then</span><span class="tok-punc">(</span><span class="tok-var">user</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">user</span><span class="tok-punc">.</span><span class="tok-var">name</span><span class="tok-punc">);</span>
<span class="tok-punc">});</span></div>
<div class="console" id="fetchConsole"></div>
</div>
<p class="note-line">T tells fetchData what shape to expect back — user.name is then type-checked, not guessed. (Network simulated here.)</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('basicBtn', 'basicConsole', function (c) {
line(c, 'ok', '10 hello TypeScript');
});
bind('arrBtn', 'arrConsole', function (c) {
line(c, 'ok', '1');
line(c, 'ok', 'a');
});
bind('mergeBtn', 'mergeConsole', function (c) {
line(c, 'ok', "{ name: 'Tisha', age: 22 }");
});
bind('constrBtn', 'constrConsole', function (c) {
line(c, 'ok', '5');
line(c, 'ok', '3');
line(c, 'ok', '5');
line(c, 'err', "logLength(123) \u2192 Error: Argument of type 'number' is not assignable to parameter of type '{ length: number }'.");
});
bind('defaultBtn', 'defaultConsole', function (c) {
line(c, 'ok', "[ 'hi' ]");
line(c, 'ok', '[ 42 ]');
});
bind('arrowBtn', 'arrowConsole', function (c) {
line(c, 'ok', "[ 'apple' ]");
line(c, 'ok', '[ true ]');
});
bind('fetchBtn', 'fetchConsole', function (c) {
line(c, '', 'fetching /api/user\u2026');
setTimeout(function () {
line(c, 'ok', 'Tisha');
}, 500);
});
})();
</script>
</div>📌 Summary
Concept | Description |
|---|---|
| Generic type placeholder |
Inference | TypeScript guesses the type automatically |
Constraints |
|
Multiple Generics |
|
Defaults |
|