If you have ever used Express with Typescript you have surely defined new types for your application. You might have defined several types for your models, or for your function arguments or return types. You definitely would have had to create just a few, especially if you are using tslint to check and lint your code.
I mention tslint just because it will mark all your variables, the ones without an explicit type, as being implicitly typed to any and of course you will get a nice red underline in your IDE or editor. This will undoubtedly push you to create more custom types.
Anyways, as always I degress…
I believe we have all been in the above mentioned scenario, and that is of course the desired consequence of using typescript. I won’t go over why you should use typescript, but there are a couple of situations which will make you think ‘Why did I decide to use Typescript??? Arghh!!!’ and even that is part of the experience .
So lets look at a scenario where typescript will make your life a little more difficult, luckily there is a way to get around this problem and continue to enjoy using typescript.
In old Javascript
In nodejs, more specifically javascript, due to the nature of the language one can fluidly create new properties on objects. I know some will say that doing so is really bad, but we have all done it and I am sure we will all continue to do it.
Take a look at the code below.
|
|
This is all fine and dandy and totally valid javascript, so this would naturally also work in nodejs. Duh…
Express
One very cool aspect of working with Express is the ability to extend the framework to support our needs. This is achieved by creating, and/or using middlewares.
Lets look, for a moment, at the Express documentation for middleware functions:
Middleware functions can perform the following tasks:
- Execute any code.
- Make changes to the request and the response objects.
- End the request-response cycle.
- Call the next middleware function in the stack.
It will happen that within your middleware you will perform some work and you will want to add the result to the request or response object for later. This may look something like this.
|
|
This is a pretty standard way of working with Express. So what is the problem?
Enter Typescript
When using typescript, you will get a compilation error from the typescript compiler if you attempt to access an undeclared property, something like:
|
|
So if we take a look at the code above and turn it into valid typescript, you will see that it does not change very much, but you will not be able to compile it because you are now accessing an undeclared property.
|
|
I am sure that like me you will start asking yourself ‘how can I get typescript to know that there is a customProperty on the Request object?’
Well there is one simple way of doing exactly that… letting the typescript compiler know that Request does indeed contain a customProperty property.
Extending Typescript declarations
The correct term is Declaration merging and it means exactly what the name states, here is the official documentation for it.
It simply means that at compilation the typescript compiler will merge separate type declarations into a single definition. Doing so will create an extended type, which will contain the properties of all the declarations together.
Looking at the code above you would extend Express and ensure that the TS compiler knows about our customProperty. Create a new definition file in your project.
|
|
The code above simply states that we are adding customProperty as an optional string to the Request interface in the Express namespace.
Now all we have to do is let the compiler know about the new interface declaration. We can do that by simply adding our custom.request.d.ts file to the tsconfig.json in the files section.
|
|
This will ensure that the typescript compiler will merge the type declaration found in our custom.request.d.ts file with the one provided by the Express framework.
This way you will not get any compilation errors because of undeclared properties. This way of extending the type declarations is very powerful and flexible. Furthermore it does not pollute the official declarations of the framework.