TypeScript: Use case of the interface merge declaration

Imagine that we want to extend the Window from anywhere in our code, making global flags, functions, APIs,… available anywhere.

How would we do that?

It’s quite simple. To do so, we need to declare the Window interface inside a global namespace.

declare global {
    interface Window {

    }
}

The namespaces are used, mostly, when we want to spread type declarations across files. But, whenever we want to extend the Window interface we don’t want to end up overwriting the type entirety, so we will attach a custom field to it.

declare global {
    interface Window {
        debug: boolean;
    }
}

Wait, wait, wait… but tell me where I should declare that kind of thing…

The most common approach is to create an ambient type declaration file (ambient.d.ts). An ambient type declaration file allows us to tell TypeScript that some variables, functions,… are globally known and defined. Usually, these local declarations are stored in a @types folder at the root of the project.

You may have done something like this: npm install @types/react

With that command you are installing the React type declarations. These declarations are “ambiental” and TypeScript knows how to work with them.

How does TypeScript know that these declarations exist?

In the tsconfig.json file, we can define a property named typeRoots. In this property, we define where additional type information can be found.

{
    "compilerOptions": {
        "target": "ES2020",
        "module": "es2020",
        "allowJs": true,
        "checkJs": true,
        "typeRoots": [
            "@types",
            "./node_modules/@types"
        ],
        "esModuleInterop": true,
    },
    "include": ["src", "@types"]
}

In the example above, @types is our local types folder where we will keep our ambient module declarations. The other is node_modules/@types where we get the ambient declaration of the libraries/dependencies that we have installed in the project (for example: @types/react).

With that setup, we will become debug available in all our JavaScript/TypeScript files. Assuming that this variable is defined and available in the global scope.

if (window.debug) {
    console.log(“Debug mode!”)
}
If you find any kind of error, something that it's not clear enough or you want me to drill down in more detail, don't hesitate to contact me.