Mastering TypeScript 3
上QQ阅读APP看书,第一时间看更新

Decorator metadata

The TypeScript compiler also includes experimental support for something called decorator metadata. Decorator metadata is metadata that is generated on class definitions in order to supplement the information that is passed into decorators. This option is called emitDecoratorMetadata, and can be added to the tsconfig.json file, as follows:

{ 
    "compilerOptions": { 
       // other options 
        "experimentalDecorators": true 
        ,"emitDecoratorMetadata": true 
    } 
} 

With this compile option in place, the TypeScript compiler will generate extra information relating to our class definitions. To see the results of this compile option, we will need to take a closer look at the generated JavaScript. Consider the following parameter decorator and class definition:

function metadataParameterDec(target: any,  
    methodName : string,  
    parameterIndex: number) { 
} 
 
class ClassWithMetaData { 
    print(  
        @metadataParameterDec  
        id: number,  
        name: string) : number { 
        return 1000; 
    } 
}

Here, we have a standard parameter decorator named metadataParameterDec, and a class definition named ClassWithMetaData. We are decorating the first parameter of the print function. If we are not using the emitDecoratorMetadata compile option, or if this option is set to false, our generated JavaScript would be defined as follows:

var ClassWithMetaData = (function () { 
    function ClassWithMetaData() { 
    } 
    ClassWithMetaData.prototype.print = function (id, name) { 
    }; 
    __decorate([ 
        __param(0, metadataParameterDec) 
    ], ClassWithMetaData.prototype, "print"); 
    return ClassWithMetaData; 
}()); 

This generated JavaScript defines a standard JavaScript closure for our ClassWithMetaData class. The code that we are interested in is near the bottom of the closure, where the TypeScript compiler has injected a method named __decorate. We will not concern ourselves with the full functionality of this __decorate method, other than to note that it contains information about the print function, and indicates that it is named print, and that it has a single parameter at index 0.

When the emitDecoratorMetadata option is set to true, the generated JavaScript will contain some extra information about this print function, as follows:

var ClassWithMetaData = (function () { 
    function ClassWithMetaData() { 
    } 
    ClassWithMetaData.prototype.print = function (id, name) { 
    }; 
    __decorate([ 
        __param(0, metadataParameterDec),  
        __metadata('design:type', Function),  
        __metadata('design:paramtypes', [Number, String]),  
        __metadata('design:returntype', Number) 
    ], ClassWithMetaData.prototype, "print"); 
    return ClassWithMetaData; 
}());

Note how the __decorate function now includes extra calls to a function named __metadata, which is called three times. The first call uses a special metadata key of 'design:type', the second uses the metadata key 'design:paramtypes', and the third call uses the metadata key 'design:returntype'. These three function calls to the __metadata function are, in fact, registering extra information about the print function itself. The 'design:type' key is used to register the fact that the print function is of type Function. The 'design:paramtypes' key is used to register the fact that the print function has two parameters—the first a Number, and the second a String. The 'design:returntype' key is used to register the return type of the print function which, in our case, is a number.