<!DOCTYPE html>
<html>
  <body>
    <ul id="log1"></ul>
    <ol id="log2"></ol>
  </body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/reflect-metadata/0.1.8/Reflect.min.js"></script>
  <script src="script.js"></script>
  <script>
    var my = new MyClass();
    globalSericeLocator.registerService(ILogService, new LogService1());
    my.sayHello();
    my.sayHello();
    my.serviceLocator = new ServiceLocator();
    my.serviceLocator.registerService(ILogService, new LogService2());
    my.sayHello();
    my.sayHello();
  </script>
</html>

abstract class ILogService {
	abstract log(msg: string): void;
}
class LogService1 implements ILogService {
	log(msg: string) {
  	console.info(msg);
    document.getElementById("log1").innerHTML += "<li>" + msg + "</li>";
  }
}
class LogService2 implements ILogService {
	log(msg: string) {
  	console.info(msg);
    document.getElementById("log2").innerHTML += "<li>" + msg + "</li>";
  }
}

class ServiceLocator {
  services: [{interfaceType: Function, instance: Object }] = [] as any;

  registerService(interfaceType: Function, instance: Object) {
    var record = this.services.find(x => x.interfaceType == interfaceType);
    if (!record) {
      record = { interfaceType: interfaceType, instance: instance};
      this.services.push(record);
    } else {
      record.instance = instance;
    }
  }
  getService(interfaceType: Function) {
    return this.services.find(x => x.interfaceType == interfaceType).instance;
  }
}
var globalSericeLocator = new ServiceLocator();

function Inject(target: Object, propKey: string): TypedPropertyDescriptor<any> {
		var propType = Reflect.getMetadata("design:type", target, propKey);
    var descriptor = {
    	get: function () { 
    	  var serviceLocator = this.serviceLocator || globalSericeLocator;
    	  return  serviceLocator.getService(propType);
    	}, configurable: true, enumerable: true
    };
    Object.defineProperty(target, propKey, descriptor);
    return descriptor;
}

class MyClass {
	@Inject
  private logService: ILogService;
  
  sayHello() {
  	this.logService.log("Hello there");
  }
}
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}