<!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 model = new Model();
    model.title = "Hello there";
    model.description = "Decorators are cool!"
    var json = serialize(model);
    document.body.innerHTML += "<h3>Model:</h3><p><pre>" + JSON.stringify(model) + "</pre></p>";
    document.body.innerHTML += "<h3>Result json:</h3><p><pre>" + json + "</pre></p>";
  </script>
</html>
// Уникальный ключ для наших метаданных
const JsonNameMetadataKey = "Habrahabr_PFight77_JsonName";
// Декоратор
function JsonName(name: string) {
    return (target: Object, propertyKey: string) => {
        // Сохраняем в метаданных переднный name
        Reflect.defineMetadata(JsonNameMetadataKey, name, target, propertyKey);
    }
}
function serialize(model: Object): string {
	var result = {};
  var target = Object.getPrototypeOf(model);
  for(var prop in model) {
  	// Загружаем сохраненное декоратором значение
  	var jsonName = Reflect.getMetadata(
    	JsonNameMetadataKey, target, prop) || prop;    
    result[jsonName] = model[prop];
  }
  return JSON.stringify(result);
}

class Model {
  @JsonName("name")
  public title: string;
  public description: string;
}
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}