Requires building the master branch of TypeScript, and the reflect-metadata polyfill.
Compile with
node built/local/tsc.js --target ES5 --experimentalDecorators --emitDecoratorMetadata --module commonjs inject.ts
| /// <reference path="node_modules/reflect-metadata/reflect-metadata.d.ts" /> | |
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | |
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); | |
| switch (arguments.length) { | |
| case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); | |
| case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); | |
| case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); | |
| } | |
| }; | |
| var __metadata = (this && this.__metadata) || function (k, v) { | |
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | |
| }; | |
| require('reflect-metadata'); | |
| function inject(target) { | |
| } | |
| var SomeClass = (function () { | |
| function SomeClass() { | |
| this.value = 'SomeClassValue'; | |
| } | |
| return SomeClass; | |
| })(); | |
| var SomeOtherClass = (function () { | |
| function SomeOtherClass() { | |
| this.value = 'SomeOtherClassValue'; | |
| } | |
| return SomeOtherClass; | |
| })(); | |
| var Injector = (function () { | |
| function Injector(typeMap) { | |
| this.typeMap = typeMap; | |
| } | |
| Injector.prototype.call = function (obj, method, extraArgs) { | |
| var _this = this; | |
| if (extraArgs === void 0) { extraArgs = []; } | |
| var result = Reflect.getMetadata('design:paramtypes', obj.constructor.prototype, method); | |
| if (typeof result === 'undefined') { | |
| result = []; | |
| } | |
| if (result instanceof Array) { | |
| return obj[method].apply(obj, result.map(function (item) { | |
| var val = _this.typeMap.get(item) || extraArgs.shift(); | |
| if (!val) { | |
| throw new Error('Could not get type info for ' + item); | |
| } | |
| return val; | |
| })); | |
| } | |
| else { | |
| throw new Error('Could not get type info'); | |
| } | |
| }; | |
| return Injector; | |
| })(); | |
| var MyClass = (function () { | |
| function MyClass() { | |
| } | |
| MyClass.prototype.myMethod = function (aClass, anotherClass, somePassedValue) { | |
| console.log(aClass.value); | |
| // SomeClassValue | |
| console.log(anotherClass.value); | |
| // SomeOtherClassValue | |
| console.log(somePassedValue); | |
| // Hello, World | |
| }; | |
| Object.defineProperty(MyClass.prototype, "myMethod", | |
| __decorate([ | |
| inject, | |
| __metadata('design:type', Function), | |
| __metadata('design:paramtypes', [SomeClass, SomeOtherClass, Object]), | |
| __metadata('design:returntype', Object) | |
| ], MyClass.prototype, "myMethod", Object.getOwnPropertyDescriptor(MyClass.prototype, "myMethod"))); | |
| return MyClass; | |
| })(); | |
| var map = new Map(); | |
| map.set(SomeClass, new SomeClass()); | |
| map.set(SomeOtherClass, new SomeOtherClass()); | |
| var injector = new Injector(map); | |
| injector.call(new MyClass(), 'myMethod', ['Hello, World']); |
| /// <reference path="node_modules/reflect-metadata/reflect-metadata.d.ts" /> | |
| import 'reflect-metadata'; | |
| declare class Map<K, V> { | |
| get(key : K): V; | |
| set(key : K, value : V); | |
| } | |
| function inject(target) { | |
| } | |
| class SomeClass { | |
| value = 'SomeClassValue'; | |
| } | |
| class SomeOtherClass { | |
| value = 'SomeOtherClassValue'; | |
| } | |
| class Injector { | |
| constructor(private typeMap : Map<Function, Object>) { | |
| } | |
| call(obj : Object, method : string, extraArgs : any[] = []) : any { | |
| var result : any[] | void = Reflect.getMetadata('design:paramtypes', obj.constructor.prototype, method); | |
| if (typeof result === 'undefined') { | |
| result = []; | |
| } | |
| if (result instanceof Array) { | |
| return obj[method]( | |
| ...result.map(item => { | |
| var val = this.typeMap.get(item) || extraArgs.shift(); | |
| if (!val) { | |
| throw new Error('Could not get type info for ' + item) | |
| } | |
| return val; | |
| }) | |
| ); | |
| } else { | |
| throw new Error('Could not get type info'); | |
| } | |
| } | |
| } | |
| class MyClass { | |
| @inject | |
| public myMethod(aClass : SomeClass, anotherClass : SomeOtherClass, somePassedValue : any) { | |
| console.log(aClass.value); | |
| // SomeClassValue | |
| console.log(anotherClass.value); | |
| // SomeOtherClassValue | |
| console.log(somePassedValue); | |
| // Hello, World | |
| } | |
| } | |
| var map = new Map(); | |
| map.set(SomeClass, new SomeClass()); | |
| map.set(SomeOtherClass, new SomeOtherClass()); | |
| var injector = new Injector(map); | |
| injector.call(new MyClass(), 'myMethod', ['Hello, World']); |