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

TypeScript Modules & Namespaces

TypeScript 2.0 Intermediate
debt(d5/e3/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list TypeScript compiler and ESLint as tools. The TypeScript compiler surfaces module resolution errors and can warn on legacy namespace usage, but it won't outright reject namespaces — ESLint with specific rules (e.g. @typescript-eslint) is needed to flag legacy namespace patterns. Neither is a default linter catch (d3), since namespace syntax is syntactically valid TypeScript; specialist configuration is required.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix is clear: replace namespace/module keywords with ES module import/export syntax and update moduleResolution config. This is more than a one-line patch (e1) because every namespace block and its consumers must be converted, but it's typically scoped to refactoring within one or a few files/components rather than a cross-cutting architectural rework.

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

Closest to 'persistent productivity tax' (e5, mapped to b5). Applies to both web and cli contexts broadly. A codebase mixing namespaces with ES modules imposes ongoing confusion for every maintainer — they must understand two module systems, tree-shaking is broken, and tooling integration degrades. It affects many work streams (bundler config, IDE navigation, dead-code elimination) but doesn't fully reshape the architecture (b7), so b5 is appropriate.

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

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field states explicitly that developers believe namespaces are the correct modern way to organise TypeScript code, when they are actually a legacy pattern superseded by ES modules. This directly contradicts how JavaScript/Node.js modules work and how modern bundlers expect code to be structured. A competent developer coming from JavaScript will confidently use namespaces and be wrong in a non-obvious way, making this a serious trap rather than merely a documented gotcha.

About DEBT scoring →

Also Known As

TypeScript namespaces module resolution ambient module declare module

TL;DR

ES modules (import/export) are the modern standard — namespaces are legacy for global scripts and ambient declarations only.

Explanation

TypeScript module: any file with an import or export statement — isolated scope, explicit dependencies. Namespace (formerly 'internal module'): namespace Foo {} — only appropriate for global script files and ambient declarations. Modern TypeScript: always prefer ES modules for better tree-shaking, tooling, and compatibility. Ambient modules: declare module 'lodash' for adding types to untyped JavaScript packages. Declaration merging: interfaces and namespaces can be merged to extend existing types.

Common Misconception

TypeScript namespaces are the correct way to organise code — namespaces are a legacy pattern; ES modules with explicit imports provide better tree-shaking and tooling support.

Why It Matters

Using namespaces in a bundler project prevents tree-shaking (all namespace code is included even if unused) and creates confusion about what is exported — ES modules are the correct default.

Common Mistakes

  • Using namespaces in modern bundled applications — use ES modules
  • Forgetting that a .ts file without import/export is a global script, not a module
  • Triple-slash references (/// <reference>) in module code — use import in modern TypeScript
  • Mixing namespace and module patterns in the same codebase

Code Examples

✗ Vulnerable
// Legacy namespace — not tree-shakeable, pollutes global scope:
namespace MyApp {
    export namespace Utils {
        export function formatDate(date: Date): string {
            return date.toISOString();
        }
    }
}
// Usage: MyApp.Utils.formatDate(new Date())
✓ Fixed
// ES Module — tree-shakeable, explicit dependencies:
// utils/date.ts:
export function formatDate(date: Date): string {
    return date.toISOString();
}

// app.ts:
import { formatDate } from './utils/date';
// Bundler includes only formatDate, not all of utils

// Ambient module for untyped JS:
declare module 'legacy-lib' {
    export function init(config: object): void;
}

Added 16 Mar 2026
Edited 22 Mar 2026
Views 55
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 1 ping F 1 ping S 1 ping S 4 pings M 2 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Perplexity 9 Amazonbot 8 Scrapy 6 Ahrefs 4 Google 4 SEMrush 4 Bing 3 Unknown AI 2 Claude 2 ChatGPT 2 Meta AI 1 PetalBot 1
crawler 42 crawler_json 4
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Use ES module syntax (import/export) not namespace or module keywords — TypeScript namespaces are legacy; configure moduleResolution: NodeNext or bundler to match your build tool
📦 Applies To
typescript 2.0 web cli
🔗 Prerequisites
🔍 Detection Hints
Legacy namespace MyApp {} syntax; triple-slash references; module resolution errors from wrong moduleResolution setting
Auto-detectable: ✓ Yes typescript eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: File


✓ schema.org compliant