TypeScript lets you add to types you do not own with declaration merging. There are three situations, and the first rule is whether the file is a module (has a top-level import or export) or a script.
- Module augmentation. In a module file,
declare module "./observable" { interface Observable<T> { map(...): ... } }. The name resolves like an import specifier, and the block merges into the original declarations as if written there. Use interfaces and namespaces; for third-party types, this is how you add a property to, say, a request type. Default exports cannot be augmented, only named ones (Handbook). - Global augmentation. In a module file,
declare global { interface Window { appVersion: string } }. Typical uses:Window, andNodeJS.ProcessEnvfor typedprocess.env. - Ambient script declarations. In a
.d.tswith no top-levelimport/export, every top-level declaration is global (interface Window {...},declare const BUILD_ID: string). The same file can holddeclare module "name" {...}to declare a package that has no types (see the declaration-files question).
Augmentations only change types. You must still write the implementation (Observable.prototype.map = ...), and the augmenting file has to be part of the program. If no file in the compilation includes it, the types do not exist.
Triple-slash directives are comments at the top of a file: /// <reference types="node" /> pulls in an @types package, /// <reference path="./x.d.ts" /> adds a file, /// <reference lib="es2015" /> adds a built-in lib. Prefer imports or tsconfig include/types. Since TS 5.5 they are not emitted into outputs unless marked preserve="true".