TypeScript has an unusual and powerful capability that most type systems lack: the ability to extend a type you do not own and cannot edit. Through declaration merging, two declarations of the same name combine into one, and through module augmentation, you can reach into a third-party package's or the global environment's type definitions and add to them. This is not a hack but a designed feature, rooted in how the language evolved to describe a JavaScript ecosystem full of libraries that attach properties dynamically, extend built-in prototypes, and expose objects that grow at runtime. Without it, every time a library's published types were slightly incomplete, or every time you wanted to add a custom property to a framework's request object, you would be forced to fork the library or abandon type safety with `any`.
This lesson covers the mechanics and the judgment around these features: how interfaces and namespaces merge, how to augment a module's or the global scope's types safely, and — critically — when this power is the right tool versus when it is a trap. Declaration merging is double-edged: used well, it lets you accurately describe a plugin-extended object or add a typed field to a framework's request, keeping a large integrated system type-safe; used carelessly, it creates spooky action at a distance, where a type changes meaning because of a declaration in a file nobody is looking at. Understanding both the how and the when is what separates an engineer who can safely integrate and extend a complex typed ecosystem from one who either fights incomplete types with `any` or pollutes the global namespace with confusing merges.