← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

TypeScript Interfaces vs Type Aliases

TypeScript 2.0 Intermediate
debt(d3/e1/b3/t5)
d3 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'default linter catches the common case' (d3). The detection_hints list TypeScript compiler and ESLint as tools. ESLint with @typescript-eslint rules (e.g. consistent-type-definitions) can flag inconsistent use of interface vs type for object shapes, catching the most common mistakes automatically at lint time.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch or single-call swap' (e1). The quick_fix states 'both work for most cases' and the fix is simply swapping `type` for `interface` (or vice versa) at the declaration site — a single-keyword change per occurrence with no cross-cutting refactor needed.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The choice applies to web and cli contexts and is tagged as syntax/types. Mixing conventions (the noted common mistake) creates a persistent but localised cognitive tax — it mainly affects the files where object shapes are declared and any consumer that needs declaration merging, not the entire architecture.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception field explicitly states developers believe interfaces and type aliases are completely interchangeable — a documented gotcha. The real differences (declaration merging vs union support) are non-obvious but well-documented, and most developers encounter this eventually when trying to augment third-party types or express union shapes.

About DEBT scoring →

Also Known As

interface type alias interface vs type

TL;DR

Both define object shapes, but interfaces are open (mergeable via declaration merging) while type aliases are closed — types are more flexible for unions and computed types.

Explanation

Interfaces (interface User {}) can be extended with extends and are automatically merged if declared twice in the same scope (useful for augmenting library types). Type aliases (type User = {}) support union types, intersection types, conditional types, and mapped types — things interfaces cannot express. Convention: prefer interface for object shapes that may be extended or implemented by classes; prefer type for unions, intersections, and computed types. In practice, both work for most cases.

Diagram

flowchart TD
    subgraph Interface
        INT[interface User<br/>name: string<br/>email: string]
        INT_MERGE[Can be merged<br/>declaration merging]
        INT_EXTEND[extends keyword<br/>for inheritance]
    end
    subgraph Type_Alias
        TYPE[type User =<br/>name: string<br/>email: string]
        TYPE_UNION[Can use union types<br/>string or number]
        TYPE_MAPPED[Can use mapped types<br/>Partial Required etc]
    end
    subgraph When_to_Use
        USE_INT[Interface: public API<br/>class contracts<br/>extendable shapes]
        USE_TYPE[Type: unions intersections<br/>computed types<br/>primitives]
    end
style INT fill:#1f6feb,color:#fff
style TYPE fill:#238636,color:#fff
style USE_INT fill:#1f6feb,color:#fff
style USE_TYPE fill:#238636,color:#fff

Common Misconception

Interfaces and type aliases are completely interchangeable — interfaces support declaration merging (extending third-party types) which type aliases do not; types support union types which interfaces do not.

Why It Matters

Choosing interface vs type affects whether the shape can be merged, extended, and expressed — using type for everything means losing declaration merging for library augmentation.

Common Mistakes

  • Using type for object shapes that need to be extended or implemented by classes — interface is clearer.
  • Using interface for union types — interfaces cannot express string | number directly; type is required.
  • Not using declaration merging for extending third-party library types — add fields to window or Express Request with interface merging.
  • Mixing conventions within a codebase — pick interface for objects and type for everything else, consistently.

Code Examples

✗ Vulnerable
// type cannot be merged for library augmentation:
type Request = { user?: User }; // Type — cannot merge
// Cannot augment Express's Request type this way

// interface cannot express union:
interface StringOrNumber = string | number; // Syntax error
✓ Fixed
// Interface for object shapes (extendable, mergeable):
interface User { id: number; name: string; }
interface Admin extends User { permissions: string[]; } // Extension

// Augment Express Request (declaration merging):
declare global {
    namespace Express { interface Request { user?: User; } }
}

// Type for unions, intersections, computed:
type ID = string | number;
type ApiResponse<T> = { data: T; status: number; };
type UserOrAdmin = User | Admin;

Added 15 Mar 2026
Edited 22 Mar 2026
Views 414
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 3 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 1 ping F 1 ping S 0 pings S 1 ping M
Google 1
No pings yesterday
ChatGPT 33 Scrapy 23 Amazonbot 16 Google 14 Perplexity 13 PetalBot 9 Ahrefs 8 SEMrush 8 Unknown AI 3 You.com 3 Bing 3 Applebot 2 Meta AI 1 Twitter/X 1
crawler 131 crawler_json 4 pre-tracking 2
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Generic typescript A generic is a placeholder for a type that gets filled in later, letting you write one function or class that works with many types while still being type-safe.

Generics let you reuse logic across types without resorting to `any`, which is the difference between safe, self-documenting code and code that silently breaks at runtime.

💡 If a function should work with many types but keep type safety, reach for `<T>` instead of `any`.

Ask Codex about Generic →
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Low
⚡ Quick Fix
Prefer type aliases for unions and computed types; prefer interfaces for object shapes you expect to extend or implement — both work for most cases
📦 Applies To
typescript 2.0 web cli
🔗 Prerequisites
🔍 Detection Hints
Using any instead of defining proper interface; interface extending another where type intersection would be clearer
Auto-detectable: ✓ Yes typescript eslint
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: File


✓ schema.org compliant