Before we begin, bear in mind that in order to use decorators, our tsconfig.json file must be configured correctly, as follows:
{ "compilerOptions": { "target": "es6", "module": "commonjs", "lib": [ "es6" ], "strict": true, "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, } }
Here, we have included the "experimentalDecorators" : true option, as well as the "emitDecoratorMetadata" : true option in order for our code to use decorators, as we did in Chapter 4, Decorators, Generics and Asynchronous Features. We have also defined that we wish to use ES6 as our compile target, and have included the es6 library in our lib definition. We will also need to install the reflect-metadata package, as follows:
npm install reflect-metadata
Let's put together a simple class decorator, and see what information we can deduce from the class. Our decorator, in the Decorator.ts file is as follows:
import 'reflect-metadata'; export function ConstructorInject(classDefinition: Function) { console.log(`classDefinition:`); console.log(`================`); console.log(`${classDefinition}`); console.log(`================`); }
Here, we are importing the reflect-metadata module, and have then created a decorator that is simply logging the value of the classDefinition argument to the console.
We can now decorate our MailServiceDi class with this decorator, and see what happens:
import { ConstructorInject } from './ConstructorInject'; @ConstructorInject export default class MailServiceDi { private _transporter: nodemailer.Transporter; private _settings: ISystemSettings; constructor(_settings?: IISystemSettings) { } }
Here, we have imported our ConstructorInject decorator, and applied it to our MailServiceDi class. Note that for the sake of brevity, we have removed the body of the constructor code that configures the _transporter property. If we now create an instance of this class, it will be as follows:
import MailServiceDi from './MailServiceDi'; var gmailDi = new MailServiceDi();
We will generate the following console output from our ConstructorInject decorator, as follows:
classDefinition: ================ class MailServiceDi { constructor(_settings) { } } ================
As we can see, the classDefinition parameter is populated with the full class definition for the MailServiceDi class. This definition, however, is not the TypeScript definition of our class, but it is the JavaScript definition of our class. This means that we have lost the type information on each of our constructor parameters, as this information is compiled away. What we do have, however, is the name of the properties that this class uses in its constructor.