DEV Community

Cover image for TypeScript Tips Part II: Declaration Merging
Nick Taylor
Nick Taylor Subscriber

Posted on • Originally published at iamdeveloper.com on

TypeScript Tips Part II: Declaration Merging

Declaration merging has been around for a while now in TypeScript. In a nutshell it lets you merge definitions of types.
There's plenty of examples in the documentation, so let's just start off with something simple.

enum HardDriveType {
    ssd,
    sata
}

enum ProcessorType {
    i3,
    i5,
    i7,
    i9
}

interface Computer {
    processor: ProcessorType;
}

interface Computer {
    hardDriveType: HardDriveType;
}

// interface has been merged
const myPC: Computer = {
    hardDriveType: HardDriveType.ssd,
    processor: ProcessorType.i9
};

// interface is merged so type checking fails since the processor property is missing
const myBadPC: Computer = {
    hardDriveType: HardDriveType.ssd,
};
Enter fullscreen mode Exit fullscreen mode

You can play around with the example in the TypeScript Playground.
So two interfaces called Computer are declared and all the properties of those interfaces are merged together into one declaration for the Computer interface. This is a simple example to show how it works, but in a real world app, you wouldn't be declaring the interface in two pieces in a file. Let's go with something more realistic.

You are using a third-party library or it's something in your project that needs to live on the window. The window has it's own type, the Window interface. This type has all the properties you'd expect to find on MDN about window.

Let's use our a fictitious 3rd party library called awesomeThing. It gets loaded onto the window object so we need to enhance the Window interface.

export interface AwesomeThing {
    doIt: () => void;
}

declare global {
    interface Window {
        awesomeThing: AwesomeThing
    }
}

// The window interface has been merged with our interface to add awesomeThing.
window.awesomeThing.doIt();

// Errors because it's not on the `Window` interface.
window.thingThatIsNotOnWindow.doIt();
Enter fullscreen mode Exit fullscreen mode

You can play around with the example in the TypeScript Playground.

If you'd like to see some real world examples in open source, look no further than a recent PR of mine that got merged to the Refined GitHub browser extension repository. I was really happy getting this PR in because it's an extension I use everyday.

Specifically, check out globals.d.ts in the project.

That's pretty much all there is to it. To summarize, declaration merging is a great way to enhance existing types.

Photo by Mike Enerio on Unsplash

Top comments (1)

Collapse
 
karlkras profile image
Karl Krasnowsky

Hey, good article!
I do have a question around .d.ts declaration file use in a react typescript project you might be able to address.
I saw an example program that was using this with other ts modules that used these interfaces without the need to explicitly importing from the type file.
I tried this with a relatively large component group and this worked great.
However, when I submitted this for review, a dev took issue with this and refused to accept it on unavailable documentation supporting standards that this was a good practice or applicable to my use, although I could demonstrate that this worked fine.
Could you confirm (or not) that this is a valid use of .d.ts declaration files?