Photo by Mike Enerio on Unsplash
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,
};
You can [play around with the example](https://www.typescriptlang.org/play/# src=enum%20HardDriveType%20%7B%0A%09ssd%2C%0A%09sata%0A%7D%0A%0Aenum%20ProcessorType%20%7B%0A%09i3%2C%0A%09i5%2C%0A%09i7%2C%0A%09i9%0A%7D%0A%0Ainterface%20Computer%20%7B%0A%09processor%3A%20ProcessorType%3B%0A%7D%0A%0Ainterface%20Computer%20%7B%0A%09hardDriveType%3A%20HardDriveType%3B%0A%7D%0A%0A%2F%2F%20interface%20has%20been%20merged%0Aconst%20myPC%3A%20Computer%20%3D%20%7B%0A%09hardDriveType%3A%20HardDriveType.ssd%2C%0A%09processor%3A%20ProcessorType.i9%0A%7D%3B%0A%0A%2F%2F%20interface%20is%20merged%20so%20type%20checking%20fails%20since%20the%20processor%20property%20is%20missing%0Aconst%20myBadPC%3A%20Computer%20%3D%20%7B%0A%09hardDriveType%3A%20HardDriveType.ssd%2C%0A%7D%3B) 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](https://github.com/Microsoft/TypeScript/blob/master/lib/lib.dom.d.ts# L16513). 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();
You can [play around with the example](https://www.typescriptlang.org/play/# src=export%20interface%20AwesomeThing%20%7B%0D%0A%09doIt%3A%20()%20%3D%3E%20void%3B%0D%0A%7D%0D%0A%0D%0Adeclare%20global%20%7B%0D%0A%09interface%20Window%20%7B%0D%0A%09%09awesomeThing%3A%20AwesomeThing%0D%0A%09%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F%20The%20window%20interface%20has%20been%20merged%20with%20our%20interface%20to%20add%20awesomeThing.%0D%0Awindow.awesomeThing.doIt()%3B%0D%0A%0D%0A%2F%2F%20Errors%20because%20it's%20not%20on%20the%20%60Window%60%20interface.%0D%0Awindow.thingThatIsNotOnWindow.doIt()%3B) 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](https://github.com/sindresorhus/refined-github/blob/master/source/globals.d.ts# L78) in the project.
That's pretty much all there is to it. To summarize, declaration merging is a great way to enhance existing types.
Comment on DEV