I love Typescript and how much it can improve your code quality, though it can sometimes give you a headache if you have not mastered the basics and do not know what a piece of code does and just "copy paste" it from somewhere, and add it to your project that you're working on.
Here I just compiled and put together a very engaging and practical use cases of "declaration merging" in TS. Follow me for more and if you need a Typescript fan who know how TS works.
Here is a link to official doc where I used it as a ref to build this work of art: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
So to being with we know that:
- In TS we can define the shape of a JS object at the type level.
- Compiler merges two (or more than two) separate declarations declared with the same name into one.
- Three groups of declaration entities:
- Namespace.
- Type.
- Value.
We can have a table to show who falls into which category:
Namespace | Type | Value |
---|---|---|
namespace |
||
enum |
||
class |
||
interface |
||
function |
||
variable |
IMPORTANT:
Knowing what is created with each declaration will help us to understand what is merged when you perform a declaration merge.
So let's look at the most basic example where we add scale
to Box
interface:
interface Box { height: number; width: number; }
interface Box { scale: number; }
let box: Box = { height: 5, width: 6, scale: 10 };
CAUTION:
You most likely also while coding where trying to change type of a property in
request
object coming from ExpressJS, and then your IDE + TSC was shouting at you that you can NOT do that.In the example above, in second
Box
we cannot change type of width to something like boolean. If you do so you'll get:
Subsequent property declarations must have the same type. Property 'width' must be of type 'number', but here has type 'boolean'.ts(2717)
Merging namespace + functions
function buildLabel(name: string): string {
return buildLabel.prefix + name + buildLabel.suffix;
}
namespace buildLabel {
export let suffix = "";
export let prefix = "Hello, ";
}
console.log(buildLabel("Sam Smith"));
This is a well known JS practice of creating a function and then extending the function further by adding properties onto the function. Here we did it in a type safe manner.
Merging namespace + enum
enum Permission { read = 1, write = 2 }
namespace Permission {
export function hasPermission(
userPermissions: number,
permission: Permission
): boolean {
return (userPermissions & permission) === permission;
}
export function combine(...perms: Permission[]): number {
return perms.reduce((acc, perm) => acc | perm, 0);
}
}
const userPerms = Permission.combine(Permission.read, Permission.write);
console.log(Permission.hasPermission(userPerms, Permission.read));
Here we are managing user permissions in an application in a very unix-like way. In this way we are utilizing enum
for predefined permissions and namespace to encapsulate utility functions. Very readable and easy to understand.
Some tips
- Mixins: Right now we cannot merge classes with other types, but we can utilize Mixins which are super powerful and I have a great example in my "nestjs-materials" GitHub repo. Go there and search for "PaginationMixin" to see its usage in practice.
kasir-barati / nestjs-materials
NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them
nestjs-materials
NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them
Some docs
-
Module augmentation:
- JavaScript modules do not support merging. Patch existing objects by importing and then updating them.
- This is the same trick we use for example in ExpressJS to define the shape of
req.user
.
See examples for module augmentation in the next slide.
Patch
process.env
:Patch
req.user
:
CAUTION:
- I usually create a new file called
node-env.d.ts
orglobal.d.ts
for this.- It becomes a module augmentation when we have a top-level
import
orexport
statement.
You can also find me on:
Instagram: https://www.instagram.com/node.js.developers.kh/
Facebook: https://www.facebook.com/kasirbarati
X: https://x.com/kasir_barati
YouTube: https://www.youtube.com/@kasir-barati
GitHub: https://github.com/kasir-barati/
Dev.to: https://dev.to/kasir-barati
Top comments (0)